<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://www.jonashietala.se/"><title>Jonas Hietala</title><id>http://www.jonashietala.se/feed.xml</id><updated>2026-05-05T08:16:39+00:00</updated><author><name>Jonas Hietala</name><email>mail@jonashietala.se</email><uri>https://www.jonashietala.se/</uri></author><link href="https://www.jonashietala.se/feed.xml" rel="self"/><link href="https://www.jonashietala.se/" rel="alternate"/><entry><title>Planning my Kubernetes homelab</title><id>http://jonashietala.se/blog/2026/05/05/planning_my_kubernetes_homelab/index.html</id><updated>2026-05-05T08:16:39+00:00</updated><link href="https://www.jonashietala.se/blog/2026/05/05/planning_my_kubernetes_homelab" rel="alternate"/><published>2026-05-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/kube/iceberg.png&quot;&gt;
&lt;figcaption&gt;The Kubernetes iceberg.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;If I’d have to describe my homelab setup via analogy I guess it would be similar to me on a unicycle carrying plates with both of my hands, or maybe a leaking barrel with water that I try to patch up with silver tape.&lt;/p&gt;
&lt;p&gt;I’ve also been Kubernetes-curious so I decided to completely redesign my homelab, centered around Kubernetes.
It was a bit painful but at least it fulfilled my need for procrastination very well.&lt;/p&gt;
&lt;section id=&quot;Overarching-goals&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Overarching-goals&quot; class=&quot;heading-ref&quot;&gt;Overarching goals&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve got three goals with the setup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Declarative, reproducible, and automated&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The big goal is to have everything declarative in a single git repository and to easily be able to bootstrap from nothing to a fully working setup.&lt;/p&gt;
&lt;p&gt;I want to use &lt;a href=&quot;https://developer.hashicorp.com/terraform/tutorials/aws-get-started/infrastructure-as-code&quot;&gt;Infrastructure as Code&lt;/a&gt; to create the Kubernetes cluster and &lt;a href=&quot;https://about.gitlab.com/topics/gitops/&quot;&gt;GitOps&lt;/a&gt; to populate it with all my services automatically from the repo.
It should be really easy to make a change; I want to move away from having to &lt;code&gt;ssh&lt;/code&gt; into the correct repo and manually do stuff.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Backups, backups, backups&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While a proper &lt;a href=&quot;https://about.gitlab.com/topics/gitops/&quot;&gt;GitOps&lt;/a&gt; setup means that infrastructure and configuration files are inherently backed up, a proper backup setup is still crucial.&lt;/p&gt;
&lt;p&gt;Ask me how I know.&lt;br&gt;
No, please don’t.&lt;/p&gt;
&lt;p&gt;I haven’t had a proper (as in &lt;em&gt;working&lt;/em&gt;) backup solution for years and this time I should have it from the start.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What if I could document my setup, so future me has a chance to understand what’s happening?
Writing documentation is boring, so I’ll write some blog posts instead.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’m a bit skeptical that I can fulfill all three goals, but if I manage 2/3 or even 1/3 it’s still a big win compared to my old setup.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Kubernetes-too-complicated&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Kubernetes-too-complicated&quot; class=&quot;heading-ref&quot;&gt;Kubernetes, too complicated?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s a fair question and the most common critique towards Kubernetes is that’s just too complicated (especially for a homelab).
Discussions online are filled with comments such as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Kubernetes has to be most complex software I’ve ever tried to learn. I eventually gave up and decided to stick with simple single machine docker-compose deployments.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=26271898&quot;&gt;trinovantes&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“Let’s use Kubernetes!”&lt;br&gt;
Now you have 8 problems&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://pythonspeed.com/articles/dont-need-kubernetes/&quot;&gt;Itamar Turner-Trauring&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;So why would I choose Kubernetes?&lt;/p&gt;
&lt;p&gt;Because, for whatever reason, Kubernetes is very popular and for every comment complaining about complexity you have comments extolling it’s virtues:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I was skeptical about Kubernetes but I now understand why it’s popular. The alternatives are all based on kludgy shell/Python scripts or proprietary cloud products.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=23358373&quot;&gt;zelly&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Kubernetes is the biggest quality-of-life improvement I’ve experienced in my career
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=26274107&quot;&gt;anchochilis&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;Having experienced the single machine docker-compose deployments, kludgy shell scripts, and proprietary cloud products; I think I need to use Kubernetes myself to be able to form an opinion on it.&lt;/p&gt;
&lt;p&gt;And in some ways, isn’t experimentation a core part homelabbing?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Tech-stack&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Tech-stack&quot; class=&quot;heading-ref&quot;&gt;Tech stack&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are &lt;em&gt;many&lt;/em&gt; valid tech choices for this kind of setup and many of them are reasonable.
I don’t know if my choices are reasonable—most were chosen because they sounded cool, others because I just picked one.&lt;/p&gt;
&lt;p&gt;Here’s list of some of the choices I made, which we’ll setup in this series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.talos.dev/&quot;&gt;Talos Linux&lt;/a&gt; for Kubernetes nodes.&lt;/p&gt;
&lt;p&gt;The coolest way to run Kubernetes.
Lightweight and secure, what’s not to like?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.hashicorp.com/terraform&quot;&gt;Terraform&lt;/a&gt; to provision VMs on Proxmox and to initialize &lt;a href=&quot;https://www.talos.dev/&quot;&gt;Talos Linux&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://cilium.io/&quot;&gt;Cilium&lt;/a&gt; for proxying, CNI, load balancer, and Gateway API provider.&lt;/p&gt;
&lt;p&gt;I opted for &lt;a href=&quot;https://cilium.io/&quot;&gt;Cilium&lt;/a&gt; as it’s one dependency replacing several alternatives (such as &lt;a href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/&quot;&gt;kube-proxy&lt;/a&gt;, &lt;a href=&quot;https://metallb.io/&quot;&gt;Metallb&lt;/a&gt;, and &lt;a href=&quot;https://traefik.io/traefik&quot;&gt;Traefik&lt;/a&gt;, which I was leaning towards at first).
Gateway API is the new thing you “should” use instead of ingress, and I wanted to try it out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://argo-cd.readthedocs.io/en/stable/&quot;&gt;ArgoCD&lt;/a&gt; for GitOps.&lt;/p&gt;
&lt;p&gt;If it was purely for myself &lt;a href=&quot;https://fluxcd.io/&quot;&gt;FluxCD&lt;/a&gt; might have been the better, simpler, choice but we might use &lt;a href=&quot;https://argo-cd.readthedocs.io/en/stable/&quot;&gt;ArgoCD&lt;/a&gt; at work and I don’t want to deal with two separate systems at the moment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/renovatebot/renovate&quot;&gt;Renovate&lt;/a&gt; to keep dependencies up-to-date.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://cloudnative-pg.io/&quot;&gt;CloudNativePG&lt;/a&gt; for Postgres on Kubernetes.&lt;/p&gt;
&lt;p&gt;I’ll also setup &lt;a href=&quot;https://github.com/timescale/timescaledb&quot;&gt;timescaledb&lt;/a&gt;, although we won’t use it in this series.
It’s just to prepare for the future migration of long-term statistics from &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://longhorn.io/&quot;&gt;Longhorn&lt;/a&gt; on NVMEs for persistent storage.&lt;/p&gt;
&lt;p&gt;Data is backed up using &lt;a href=&quot;https://github.com/backube/volsync&quot;&gt;VolSync&lt;/a&gt; and &lt;a href=&quot;https://restic.net/&quot;&gt;Restic&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jimsalterjrs/sanoid&quot;&gt;Sanoid, Syncoid&lt;/a&gt; and &lt;a href=&quot;https://kopia.io/&quot;&gt;Kopia&lt;/a&gt; for backup archive management.&lt;/p&gt;
&lt;p&gt;Backups are snapshotted and stored in ZFS, which are also encrypted and shipped off-site to Backblaze for storage in the cloud.
Backups from &lt;a href=&quot;https://longhorn.io/&quot;&gt;Longhorn&lt;/a&gt; and Postgres arrives to ZFS via &lt;a href=&quot;https://garagehq.deuxfleurs.fr/&quot;&gt;Garage&lt;/a&gt;, a self-hosted S3 service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://goauthentik.io/&quot;&gt;Authentik&lt;/a&gt; as an identity provider and single-sign-on platform.&lt;/p&gt;
&lt;p&gt;It’s nice to not have to login manually everywhere.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Huh. Displayed like this it looks like a lot, but fear not! It’ll be worth it in the end.&lt;/p&gt;
&lt;p&gt;In the next part we’ll start by creating VMs and getting a Kubernetes cluster up and running.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>From GitHub to Codeberg/Forgejo</title><id>http://jonashietala.se/blog/2026/04/28/from_github_to_codebergforgejo/index.html</id><updated>2026-05-04T18:29:32+00:00</updated><link href="https://www.jonashietala.se/blog/2026/04/28/from_github_to_codebergforgejo" rel="alternate"/><published>2026-04-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;Respect your users and their confidence in you, “Microsoft” GitHub.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://github.com/orgs/community/discussions/65343#discussioncomment-6937004&quot;&gt;Ethkuil&lt;/a&gt;, Updates to your GitHub Feed &lt;a href=&quot;https://github.com/orgs/community/discussions/65343&quot;&gt;#65343&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;After years of waffling around I finally bit the bullet and migrated away from &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; onto &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; and a private &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; instance.
If &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; is &lt;a href=&quot;https://www.gentoo.org/news/2026/02/16/codeberg.html&quot;&gt;good enough for Gentoo&lt;/a&gt; then it’s good enough for me.&lt;/p&gt;
&lt;section id=&quot;Whats-the-problem-with-GitHub&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Whats-the-problem-with-GitHub&quot; class=&quot;heading-ref&quot;&gt;What’s the problem with GitHub?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One part of my &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; aversion is me being anti the big American tech corporations for ideological reasons.
I’d like to reduce my usage and dependence of Google/Facebook/Apple/Microsoft/Amazon etc where I can and moving away from &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; fits that goal nicely.&lt;/p&gt;
&lt;p&gt;The other reason is GitHub’s enshittification.
&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; has been slow and slightly buggy for years and it’s not getting better.
They push out &lt;a href=&quot;https://github.com/orgs/community/discussions/65343&quot;&gt;badly planned features&lt;/a&gt; while shipping &lt;a href=&quot;https://github.com/actions/runner/issues/3792&quot;&gt;this kind of code in GitHub actions runner&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;!/bin/bash&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;variable other readwrite assignment shell&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;keyword operator assignment shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string unquoted shell&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control while shell&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;support function double-brace begin shell&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;meta group expansion parameter shell&quot;&gt;&lt;span class=&quot;punctuation definition variable shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;variable other readwrite shell&quot;&gt;SECONDS&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator logical shell&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;meta group expansion parameter shell&quot;&gt;&lt;span class=&quot;punctuation definition variable shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;variable other readwrite shell&quot;&gt;1&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;support function double-brace end shell&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator logical continue shell&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;keyword control do shell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function colon shell&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control done shell&quot;&gt;done&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(This apparently broke Zig and &lt;a href=&quot;https://web.archive.org/web/20251127021007/https://ziglang.org/news/migrating-from-github-to-codeberg/&quot;&gt;caused them to leave for Codeberg&lt;/a&gt;.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may not like it but this is what peak vibe coding looks like
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://github.com/actions/runner/issues/3792#issuecomment-3234548632&quot;&gt;mawkler&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;I know it’s a snarky comment, but with a CEO that says “&lt;a href=&quot;https://web.archive.org/web/20251127034621/https://www.businessinsider.com/github-ceo-developers-embrace-ai-or-get-out-2025-8&quot;&gt;embrace AI or get out&lt;/a&gt;” then it’s hard to resist.&lt;/p&gt;
&lt;p&gt;There’s empirical data to back up GitHub’s unreliability; just check out these uptime logs (taken 2026-04-27 from third party sites since the official status page predictably lies):&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/gh_codeberg/uptime_mrshu.png&quot;&gt;
&lt;figcaption&gt;Screenshot from &lt;a href=&quot;https://mrshu.github.io/github-statuses/&quot;&gt;https://mrshu.github.io/github-statuses/&lt;/a&gt;
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/gh_codeberg/damrnelson_uptime.png&quot;&gt;
&lt;figcaption&gt;Screenshot from &lt;a href=&quot;https://damrnelson.github.io/github-historical-uptime/&quot;&gt;https://damrnelson.github.io/github-historical-uptime/&lt;/a&gt;
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;They don’t call it “Microslop” for nothing.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Self-hosted-managed&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Self-hosted-managed&quot; class=&quot;heading-ref&quot;&gt;Self-hosted + managed&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; is based on &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt;, which is great to self-host.
I’ve had it running a few weeks when I’ve been playing with my homelab and it feels &lt;em&gt;exceptionally&lt;/em&gt; fast.
The web UI is super responsive and I frequently have to double-check that I pushed as it finished so quickly.&lt;/p&gt;
&lt;p&gt;I would love to have the speed and privacy for all my repositories but I’ve got some that I want to be public (the &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;source for this site&lt;/a&gt; for example).
I considered a few different setups:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Sync back changes to GitHub via Forgejo’s built-in GitHub sync?&lt;/p&gt;
&lt;p&gt;(Keeping GitHub active would defeat the point a little though.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sync changes from my &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; instance to &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;(Maybe annoying to manage multiple repos?)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Only use &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;(I’d lose speed and privacy for my private repos.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Expose my &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; instance running in my homelab?&lt;/p&gt;
&lt;p&gt;(The internet is a scary place.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup a public &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; on my Hetzner VPS?&lt;/p&gt;
&lt;p&gt;(I’d still have to protect it and manage traffic.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the end I decided to use &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; as for my public-facing repositories and &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; as my main interface (for both public and private repos).&lt;/p&gt;
&lt;p&gt;Some of my public repos are close to read-only (&lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;this site’s source&lt;/a&gt; for instance) so I’ve &lt;a href=&quot;https://forgejo.org/docs/next/user/repo-mirror/&quot;&gt;setup a mirror&lt;/a&gt; where &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; will push changes to &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; automatically.
However, it’s weird to &lt;em&gt;also&lt;/em&gt; pull changes from &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; to &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt;.
I guess I could setup a script to do it, but pull requests from others are rare enough that I can do it manually.
Other repos (such as &lt;a href=&quot;https://codeberg.org/treeman/tree-sitter-djot&quot;&gt;tree-sitter-djot&lt;/a&gt;) are left alone as they’re more collaborative in nature and I can’t be bothered to keep two sources in sync.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Is-it-good&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Is-it-good&quot; class=&quot;heading-ref&quot;&gt;Is it good?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yes, both &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; and &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; are very good.
They are snappy and speedy and there are no features I miss from either &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; or &lt;a href=&quot;https://about.gitlab.com/&quot;&gt;GitLab&lt;/a&gt; (and plenty I’m glad to avoid—getting AI shoved into every crevice for instance).&lt;br&gt;
(Yes, I used an em-dash on purpose.)&lt;/p&gt;
&lt;p&gt;At the moment &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; is admittedly having periods with pretty bad performance issues.
This is because they’ve been under a DDOS attack for quite some time, which has been frustrating.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I frequently switch between my laptop and desktop, and sync my work by pushing/pulling git repos.
The performance of my private &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; has been fantastic for this purpose, and as a bonus allows me to dodge the negative DDOS effects.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;The-migration&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-migration&quot; class=&quot;heading-ref&quot;&gt;The migration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The migration wasn’t difficult, just a bit repetitive.&lt;/p&gt;
&lt;p&gt;For private repositories I just deleted them from &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; and pushed them to &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Public repositories had a few more steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Push them to &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Push them to &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a header redirecting to &lt;a href=&quot;https://codeberg.org/&quot;&gt;Codeberg&lt;/a&gt; similar to this:&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;This repository has moved to &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;https://codeberg.org/treeman/jonashietala&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This GitHub copy is a frozen archive. New commits, issues, and pull requests should go to Codeberg.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Archive them on &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><title>A work week one bag travel</title><id>http://jonashietala.se/blog/2026/03/10/a_work_week_one_bag_travel/index.html</id><updated>2026-03-31T05:07:39+00:00</updated><link href="https://www.jonashietala.se/blog/2026/03/10/a_work_week_one_bag_travel" rel="alternate"/><published>2026-03-10T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;Life begins at the end of your comfort zone.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Neale Donald Walsch
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;I’m lucky that I have a job where I can work remotely as it allows me to &lt;a href=&quot;/blog/2019/10/18/we_moved_away_from_the_city/&quot;&gt;live in a small community&lt;/a&gt; where there are no tech jobs anywhere close.
It does require me to travel a few weeks per year to the office but I don’t mind that much as I appreciate minor dozes of socializing occasionally.&lt;/p&gt;
&lt;p&gt;I recently spent five nights on a trip with only a single backpack and it was a surprisingly great experience.&lt;/p&gt;
&lt;section id=&quot;How-I-used-to-travel&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#How-I-used-to-travel&quot; class=&quot;heading-ref&quot;&gt;How I used to travel&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/old_bags.jpg&quot;&gt;
&lt;figcaption&gt;I’ve previously used these two bags for my trips.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I’ve had these work trips for years and I didn’t put too much thought into &lt;em&gt;how&lt;/em&gt; to travel.
Like most people I simply filled a suitcase that I checked in together with a backpack that I brought on the airplane.&lt;/p&gt;
&lt;p&gt;I didn’t quite know how much to pack so I always packed a little more than I needed.
For example, if I’m away 5 nights then I brought 7 pairs of underwear (if disaster strikes &lt;em&gt;twice&lt;/em&gt;).
When I returned I always had a bunch of unused clothes, but that felt better than having to little.&lt;/p&gt;
&lt;p&gt;Because I had so much space I could bring a lot of things; my own pillow, a handful of books, &lt;a href=&quot;https://boardgamegeek.com/boardgame/184267/on-mars&quot;&gt;gigantic boardgames&lt;/a&gt;, and I still had space left to bring back lots of gifts.&lt;/p&gt;
&lt;section id=&quot;What-bags&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#What-bags&quot; class=&quot;heading-ref&quot;&gt;What bags?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve had two backpacks that I used to travel with:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.dsgear.com/collections/backpacks&quot;&gt;Datsusaru&lt;/a&gt; Battlepack Core&lt;/p&gt;
&lt;p&gt;It’s a really sturdy backpack that’s great to bring to BJJ training, but it’s very heavy and it’s not ideal as a traveling bag.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://m-tac.pl/en/&quot;&gt;M-Tac&lt;/a&gt; Backpack Urban Line&lt;/p&gt;
&lt;p&gt;I bought this bag recently but I wasn’t too impressed.
It was too small for a traveling bag and the zipper broke after just a few trips.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;The zipper breaking made me go online and research new traveling backpacks, which gave me the idea to try out one bag travel.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’ve had a few suitcases that have broken down but I can’t remember the brand of.
Most recently I’ve been using the &lt;a href=&quot;https://www.samsonite.se/essens-spinner-69cm--alpine-green/146911-4705.html?utm_source=transactional&amp;amp;utm_medium=email&amp;amp;utm_campaign=order-confirmation-email&quot;&gt;Samsonite Essens 69cm&lt;/a&gt; that have held out great so far.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;One-bag-travel&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#One-bag-travel&quot; class=&quot;heading-ref&quot;&gt;One bag travel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve been spending five nights away 4–5 times a year on business travels.
It’s not a crazy amount but also not negligible, so I figured it’s worth trying to optimize them a bit.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://www.youtube.com/watch?v=CbsJ2mxuJwM&quot;&gt;one bag travel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I was reasonably comfortable during my travels there’s a few things that intrigued me about one bag travel:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
I wouldn’t have to roll around a big suitcase.
&lt;/li&gt;
&lt;li&gt;
The trip would be more streamlined without having to check-in and wait for the luggage during flights.
&lt;/li&gt;
&lt;li&gt;
I wouldn’t have to worry about lost luggage (although to be fair, so far I haven’t had that happen to me).
&lt;/li&gt;
&lt;li&gt;
No more trying to find space for my suitcase on the train, or worrying that I won’t see if someone decides to grab it and walk off the train.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In short, the actual trip would be more convenient and less worrisome…&lt;br&gt;
If I could make it fit.&lt;/p&gt;
&lt;section id=&quot;The-packing-list&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#The-packing-list&quot; class=&quot;heading-ref&quot;&gt;The packing list&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/things.jpg&quot;&gt;
&lt;figcaption&gt;All the stuff I packed into a bag for a week of travel.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Water bottle&lt;/p&gt;
&lt;p&gt;I later decided not to bring it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;5 pair of socks and underwear&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;3 t-shirts, 1 long-sleeve t-shirt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 slightly thicker long-sleeve shirt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Training gear for Submission Wrestling&lt;/p&gt;
&lt;p&gt;Shorts, rashguard, spats, knee pads, and mouth guard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 pair of pants&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mobile phone charger&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;a href=&quot;https://frame.work/se/en/laptop13&quot;&gt;Framework 13&lt;/a&gt; laptop + charger&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Laptop–headphone cable&lt;/p&gt;
&lt;p&gt;I also brought the &lt;a href=&quot;https://www.sony.se/electronics/horlurar-med-huvudband/wh-1000xm3&quot;&gt;Sony WH-1000X M3&lt;/a&gt; noise canceling headphones that I wore during the trip.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://remarkable.com/products/remarkable-2&quot;&gt;Remarkable 2&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A bag for dirty clothes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Toothbrush &amp;amp; toothpaste&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Power bank&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vitamins &amp;amp; medicine&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nail clippers, tape, Whoop body holder&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Earbuds &amp;amp; sleep mask&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A book—the first two books in the &lt;a href=&quot;https://bookdna.com/books-in-order/the-murderbot-diaries&quot;&gt;Murderbot Diaries&lt;/a&gt; series.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Things-to-wear&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Things-to-wear&quot; class=&quot;heading-ref&quot;&gt;Things to wear&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/to_wear.jpg&quot;&gt;
&lt;figcaption&gt;Clothes I wore during the travel.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I saw the advice that the clothes you travel with is also very important.
They have a point.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pants with large pockets with zippers.&lt;/p&gt;
&lt;p&gt;I could use the pants the whole week if I wanted to.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I saw the advice that &lt;a href=&quot;https://www.youtube.com/watch?v=8Z2mgyHXQYI&quot;&gt;one bag travel is dead&lt;/a&gt; and that 1.5 bag travel is the future, where you should bring a sling and put things like your wallet and phone there.
Meh, I brought a pair of pants with bigger pockets instead.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A Houdini hoodie.&lt;/p&gt;
&lt;p&gt;Really warm and cozy, should last the whole week.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A thin jacket.&lt;/p&gt;
&lt;p&gt;Paired with the hoodie it provides a decent enough protection against the weather.
I’m not going on a hiking trip; I’ll be moving between the office, the hotel, and restaurants.&lt;/p&gt;
&lt;p&gt;It’s also thin enough so I can fit it into the fully packed backpack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A cap and gloves.&lt;/p&gt;
&lt;p&gt;I’m traveling in Sweden, it’s still fairly cold here.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;What-I-wish-I-brought&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#What-I-wish-I-brought&quot; class=&quot;heading-ref&quot;&gt;What I wish I brought&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
It was a bit too cold on some days. A warmer jacket, long-johns, or a nudge would’ve been good.
&lt;/li&gt;
&lt;li&gt;
The next &lt;a href=&quot;https://bookdna.com/books-in-order/the-murderbot-diaries&quot;&gt;Murderbot&lt;/a&gt; book. The first was fantastic!
I had to visit a local book store where I bought &lt;a href=&quot;https://en.wikipedia.org/wiki/Lock_In&quot;&gt;Lock In&lt;/a&gt;. Loved that too.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Gearing-up&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Gearing-up&quot; class=&quot;heading-ref&quot;&gt;Gearing up&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before I could try out one bag travel I had to get a new backpack.
I ended up with the &lt;a href=&quot;https://fyro.co/products/fyro-levo-backpack&quot;&gt;Fyro Levo 30L backpack&lt;/a&gt; mostly because the creator had a bunch of cool videos about bags…
As shipping was expensive I also got their &lt;a href=&quot;https://fyro.co/products/packing-cubes&quot;&gt;packing cubes&lt;/a&gt;, the &lt;a href=&quot;https://fyro.co/products/retractable-key-leash&quot;&gt;retractable key leash&lt;/a&gt;, and a &lt;a href=&quot;https://fyro.co/products/fyro-citta-sling&quot;&gt;1L sling&lt;/a&gt; (that I didn’t use).&lt;/p&gt;
&lt;p&gt;This isn’t a review of their stuff; there’s probably better options out there but I’m too inexperienced to say.
Maybe I should’ve gotten the 36L backpack, and the sling was an unnecessary purchase, but other than that I’ve been very happy with the Fyro products.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Packing-in&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Packing-in&quot; class=&quot;heading-ref&quot;&gt;Packing in&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Will it fit?&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/things_with_cubes.jpg&quot;&gt;
&lt;figcaption&gt;All clothes are packed into the packing cubes.
One cube with the Submission Wrestling training clothes,
one with underwear,
and the largest with the rest of the clothes.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;Packing cubes are amazing.
This is the first time I’ve used them and now I wonder: how could I travel without them?&lt;/p&gt;
&lt;p&gt;The Fyro cubes compress, important if you want to manage space.
It would’ve been very difficult to fit all clothes in the bag without them.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/cubes_in_bag.jpg&quot;&gt;
&lt;figcaption&gt;The packing cubes fits into the main compartment perfectly.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/inner_pockets.jpg&quot;&gt;
&lt;figcaption&gt;Medicine, earplugs, mouth guard, and other stuff went into these pockets in the main compartment.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/electronics.jpg&quot;&gt;
&lt;figcaption&gt;Laptop, Remarkable goes in the back.
The electronics compartment is a little tight with the charger, power bank, and some other stuff, but it closes.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/front.jpg&quot;&gt;
&lt;figcaption&gt;The quick access compartment in the front with toothpaste and mobile charger.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;One of the biggest critiques against the bag is that the pockets here are very loose as things might fall out.
When the bag is fully packed this has not been my experience—almost the reverse.
Fully packed, it’s a bit too tight. But empty they’re too loose.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/key_chain.jpg&quot;&gt;
&lt;figcaption&gt;Keys and travel documents in the “passport” pocket right next to the back.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/fully_packed.jpg&quot;&gt;
&lt;figcaption&gt;The fully packed bag.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I did fit everything I wanted to bring.
Although I skipped the water bottle it would’ve fit into the water bottle holder on the side.
Maybe I’ll bring it next time.&lt;/p&gt;
&lt;p&gt;The fully packed bag weighed in at 7.3 kg.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;On-the-road&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#On-the-road&quot; class=&quot;heading-ref&quot;&gt;On the road&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/book_and_jacket.jpg&quot;&gt;
&lt;figcaption&gt;I managed to push down my jacket, gloves, cap, and book into the front pocket.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I do love the large front compartment.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/hanging_on_door.jpg&quot;&gt;
&lt;figcaption&gt;The Levo has a small loop to hang up the bag in the bathroom. Nice.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/under_train_seat.jpg&quot;&gt;
&lt;figcaption&gt;With some force I could fit the bag under the seat in front of me in the train.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/under_seat_sas.jpg&quot;&gt;
&lt;figcaption&gt;The bag under the seat in the domestic SAS flight.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I was a bit worried that the bag wouldn’t fit under the front seat but it worked out well.
I didn’t take a picture of it but it fit in the overhead compartment during the flight too.&lt;/p&gt;
&lt;p&gt;Although the extra space of the 36L backpack would’ve been greatly appreciated I fear that it might have made the bag too large to fit under the seat.
In the end I think I prefer the convenience of having the bag under the seat over the extra 6L of space.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;From-hotel-to-office&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#From-hotel-to-office&quot; class=&quot;heading-ref&quot;&gt;From hotel to office&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/one_bag/without_cubes.jpg&quot;&gt;
&lt;figcaption&gt;Bag without packing cubes.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The bag was also used to transport the laptop and other electronics between the hotel and office.
I was worried that a huge bag would be a chore to bring but that’s been a non-issue.
The only minor problem is that the bag doesn’t stand by itself without the packing cubes.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Pros-and-cons&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Pros-and-cons&quot; class=&quot;heading-ref&quot;&gt;Pros and cons&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;One’s destination is never a place, but a new way of seeing things.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Henry Miller
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;Overall I’ve really enjoyed my one bag traveling experience.
I managed to fit into a single bag and the trip was a lot easier and more streamlined.&lt;/p&gt;
&lt;p&gt;There are however some downsides that bothers me quite a bit:&lt;/p&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I couldn’t bring &lt;a href=&quot;https://boardgamegeek.com/boardgame/371330/luthier&quot;&gt;Luthier&lt;/a&gt;, my new favorite boardgame on the trip.&lt;/p&gt;
&lt;p&gt;My work trips have been one of the best ways to reduce my boardgame list-of-shame (bought and unplayed boardgames).
Or to play my favorite games again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There’s not enough space to bring back gifts, such as clothes or LEGO.&lt;/p&gt;
&lt;p&gt;Then again, maybe I don’t need to always bring back gifts?
Or maybe small gifts are good enough?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I can’t go nuts in the local book stores.&lt;/p&gt;
&lt;p&gt;Last time I brought back five new fantasy and sci-fi books.
This time I bought a small book that I could fit at the back above the laptop.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;I haven’t yet decided if I shall continue with the one bag travel, or if I shall start checking in a suitcase again.
Either way it’s been eye opening how much you can do with a regular backpack.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>2025 in review</title><id>http://jonashietala.se/blog/2026/01/03/2025_in_review/index.html</id><updated>2026-01-08T10:49:16+00:00</updated><link href="https://www.jonashietala.se/blog/2026/01/03/2025_in_review" rel="alternate"/><published>2026-01-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s time for a &lt;a href=&quot;/blog/tags/yearly_review&quot;&gt;yearly review&lt;/a&gt; again. Time flies.&lt;/p&gt;
&lt;section id=&quot;Nerdy-things-I-enjoyed&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Nerdy-things-I-enjoyed&quot; class=&quot;heading-ref&quot;&gt;Nerdy things I enjoyed&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I read a few books this year.&lt;/p&gt;
&lt;p&gt;The whole &lt;a href=&quot;https://www.penguinrandomhouse.com/series/43C/dungeon-crawler-carl/&quot;&gt;Dungeon Crawler Carl&lt;/a&gt; series was absolutely amazing and it quickly jumped up to one of my favorite series of all time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I can’t be held accountable for everything I’ve ever said to a stripper.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Princess Donut
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Board games are great.&lt;/p&gt;
&lt;p&gt;I still don’t play nearly as much as I’d like to but my kids are quickly growing up and to my eternal joy they’re all interested in board games!
Isidor (8) has been loving &lt;a href=&quot;https://boardgamegeek.com/boardgame/329082/radlands&quot;&gt;Radlands&lt;/a&gt;, Loke (5) likes &lt;a href=&quot;https://boardgamegeek.com/boardgame/347137/chronicles-of-avel&quot;&gt;Chronicles of Avel&lt;/a&gt;, and Freja (3) loves &lt;a href=&quot;https://boardgamegeek.com/boardgame/235655/dragons-breath&quot;&gt;Dragon’s Breath&lt;/a&gt;.
My personal favorite is &lt;a href=&quot;https://boardgamegeek.com/boardgame/371330/luthier&quot;&gt;Luthier&lt;/a&gt; and I think it might be my absolute favorite game right now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Computer games have made a small comeback.&lt;/p&gt;
&lt;p&gt;As my kids have been gaming more I’ve regained a little bit of interest in gaming too.
I’ve been playing a little &lt;a href=&quot;https://store.steampowered.com/app/1621690/Core_Keeper/&quot;&gt;Core Keeper&lt;/a&gt; and &lt;a href=&quot;https://www.beyondallreason.info/&quot;&gt;Beyond All Reason&lt;/a&gt; with Isidor and it felt really fun.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2025/10/29/packing_neovim_with_fennel/&quot;&gt;Migrated my Neovim config to Fennel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Eh, it was fun to play with a new language.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Things-I-accomplished&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Things-I-accomplished&quot; class=&quot;heading-ref&quot;&gt;Things I accomplished&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I &lt;a href=&quot;/blog/2025/&quot;&gt;wrote 12 blog posts&lt;/a&gt;, not great, not terrible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I managed to push back my fantasy writing ambitions to the future.&lt;/p&gt;
&lt;p&gt;It’s important as I tend to get stuck on things, preventing me from making progress in other parts.
I really don’t have the time or energy to try to write a fantasy book &lt;em&gt;right now&lt;/em&gt;, but making my brain see that wasn’t easy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2025 was the first full year running my company.&lt;/p&gt;
&lt;p&gt;I’m still consulting for the same company I started out with and I enjoy it.
It feels good to say that I haven’t blown it completely just yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2025/08/28/ill_only_buy_devices_with_grapheneos/&quot;&gt;Switched to GrapheneOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I took a big step forward in de-Googling and to increase my personal security by moving to &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt;.
I’m super happy about it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2025/03/25/lets_build_a_voron_0/&quot;&gt;Built my second 3D-printer&lt;/a&gt;, a VORON 0.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/zero_with_mods.jpg&quot;&gt;
&lt;figcaption&gt;My VORON 0.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It’s good! It’s fun! And I’m already planning my next printer…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We &lt;a href=&quot;/blog/2025/06/04/ditching_sonos_for_music_assistant/&quot;&gt;migrated away from Sonos&lt;/a&gt; in our Kitchen.&lt;/p&gt;
&lt;p&gt;We got tired of buggy vendor lock-in and now we use my own &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; based setup.
If things break we can now blame me instead of Sonos.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I built my server first rack to host a new homelab server.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/first_rack/rack_ugly_cables.jpg&quot;&gt;
&lt;figcaption&gt;A server rack with homelab stuff.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I still need to cleanup the cables and write a blog post about it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Tentative-plansgoalswishes-for-2026&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Tentative-plansgoalswishes-for-2026&quot; class=&quot;heading-ref&quot;&gt;Tentative plans/goals/wishes for 2026&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go on some roller coasters with the family.&lt;/p&gt;
&lt;p&gt;We’re planning to go to Liseberg in Göteborg and I know the kids will love it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lose weight and build muscle.&lt;/p&gt;
&lt;p&gt;I’ve been having a rough year training and health wise.
Not being able to get a consistent strength training routine, inconsistent sleep, and &lt;a href=&quot;/blog/2023/03/14/battling_burnout/&quot;&gt;spouts of depression&lt;/a&gt; has made me gain too much weight again.&lt;/p&gt;
&lt;p&gt;Getting it sorted should (must) be a high priority this year.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get our own training space for our martial arts club.&lt;/p&gt;
&lt;p&gt;I’ve been wanting to get our own place for quite a while and I feel that we need to make it happen sooner rather than later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Develop a company product MVP.&lt;/p&gt;
&lt;p&gt;While I enjoy the consulting work I do at the moment my goal is to one day have a project of my own that can earn me money.
I have a couple of ideas I want to pursue and I was going to do it in 2025 but I didn’t get far enough for that.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Migrate my homelab to the recently built server and expand on it.&lt;/p&gt;
&lt;p&gt;I have this newly built server that’s just sitting idle.
I need to migrate my old services to it and I’ve got ideas for lots of stuff I want to put there.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><title>3D printer repairing and modding</title><id>http://jonashietala.se/blog/2025/12/02/3d_printer_repairing_and_modding/index.html</id><updated>2026-04-01T06:39:23+00:00</updated><link href="https://www.jonashietala.se/blog/2025/12/02/3d_printer_repairing_and_modding" rel="alternate"/><published>2025-12-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/modded_front.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve had my &lt;a href=&quot;/series/voron_trident&quot;&gt;VORON Trident&lt;/a&gt; for 2 years and I’ve run it for 2600 hours.
Overall I’m happy with the printer but I’ve been itching to make some more mods to it.
Having finally finished the &lt;a href=&quot;/blog/2025/03/25/lets_build_a_voron_0&quot;&gt;VORON 0&lt;/a&gt; (&lt;a href=&quot;/blog/2025/05/02/voron_0_mods&quot;&gt;with mods&lt;/a&gt;) I now have a backup printer I can use to rescue myself when I screw up.&lt;/p&gt;
&lt;p&gt;As the printer was starting to crap out with &lt;a href=&quot;/blog/2024/03/01/lets_build_a_voron_major_failure/&quot;&gt;a leadscrew starting to grind down again&lt;/a&gt;, the chamber thermistor stopped working, and PLA clogging up the Rapido hotend &lt;em&gt;again&lt;/em&gt; it was time for a bit of a rebuild.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Even my &lt;a href=&quot;/blog/2025/03/25/lets_build_a_voron_0&quot;&gt;VORON 0&lt;/a&gt; ran into an issue where the bed stopped heating up.
This happened at the &lt;em&gt;same time&lt;/em&gt; as all the issues with the &lt;a href=&quot;/series/voron_trident&quot;&gt;Trident&lt;/a&gt; started appearing.&lt;/p&gt;
&lt;p&gt;So much for having a backup printer!&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;The-plan&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-plan&quot; class=&quot;heading-ref&quot;&gt;The plan&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Besides fixing the printer I also wanted to prepare for a multi-color solution such as the &lt;a href=&quot;https://github.com/ArmoredTurtle/BoxTurtle&quot;&gt;Box Turtle&lt;/a&gt; and make some quality of life changes.&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;Replace the problematic leadscrew with a replacement part I received from LDO and replace the POM nuts on the other leadscrews.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;#Inverted-electronics&quot;&gt;Install the Inverted electronics&lt;/a&gt; mod.&lt;/p&gt;
&lt;p&gt;I’ve been using the &lt;a href=&quot;/blog/2024/02/27/lets_build_a_voron_more_mods/#RockNRoll&quot;&gt;RockNRoll&lt;/a&gt; mod to give access to the electronics compartment by tilting the printer backwards.
The &lt;a href=&quot;https://mods.vorondesign.com/details/pXkXHVIUbqSWqQKJISczw&quot;&gt;Inverted electronics&lt;/a&gt; mod would instead allow me to lift the bottom plate to access the electronics compartment and I want to do it before installing a &lt;a href=&quot;https://github.com/ArmoredTurtle/BoxTurtle&quot;&gt;Box Turtle&lt;/a&gt; on top of the printer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replace the Stealthburner with the &lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky&quot;&gt;Jabberwocky&lt;/a&gt; toolhead.&lt;/p&gt;
&lt;p&gt;This introduced a series of changes:&lt;/p&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
&lt;p&gt;Move to an umbilical setup with the &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt; toolboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href=&quot;https://docs.vorondesign.com/tuning/sensorless.html&quot;&gt;sensorless homing&lt;/a&gt; to get rid of the Y drag chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replace TAP with the &lt;a href=&quot;https://lab4450.com/product/original-beacon-3d-surface-scanner/&quot;&gt;Beacon probe&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, &lt;a href=&quot;#Building-the-Jabberwocky&quot;&gt;install the Jabberwocky&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Replacing-the-POM-nuts&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Replacing-the-POM-nuts&quot; class=&quot;heading-ref&quot;&gt;Replacing the POM nuts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve had issues before where one of the &lt;a href=&quot;/blog/2024/03/01/lets_build_a_voron_major_failure/&quot;&gt;POM nuts were ground down&lt;/a&gt; and I felt it was happening again.
The printer didn’t completely fail like before but it was sometimes getting really bad first layers in that same corner and the Z probe was occasionally failing to configure Z tilt.&lt;/p&gt;
&lt;p&gt;I replaced all three POM nuts together with the whole lead screw (I got a new one sent to me by LDO the first time it failed but I hadn’t installed it yet).&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/pom_nuts.jpg&quot;&gt;
&lt;figcaption&gt;Dust on the lead screw and all three nuts show signs of damage, although the leftmost is clearly worse off.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This is apparently a common problem with some LDO kits that have coated lead screws.
I still have two of the old ones that I may have to replace in the future.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Inverted-electronics&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Inverted-electronics&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://mods.vorondesign.com/details/pXkXHVIUbqSWqQKJISczw&quot;&gt;Inverted electronics&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve been looking at the &lt;a href=&quot;https://mods.vorondesign.com/details/pXkXHVIUbqSWqQKJISczw&quot;&gt;Inverted electronics&lt;/a&gt; mod even before finishing my Trident printer.
But it wasn’t possible with the &lt;a href=&quot;https://pif.voron.dev/&quot;&gt;Print It Forward&lt;/a&gt; service I used to print parts for my first 3D printer,
and after the printer was completed I didn’t feel the need to redo the wiring again.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/electronics_before.jpg&quot;&gt;
&lt;figcaption&gt;Wiring before ripping it all out.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/inverted_under.jpg&quot;&gt;
&lt;figcaption&gt;Underside of the printer with the inverted rails installed.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/inverted_power.jpg&quot;&gt;
&lt;figcaption&gt;Installing the first components on the rails.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/inverted_wiring.jpg&quot;&gt;
&lt;figcaption&gt;The electronics are reinstalled and up and running.
This is not the final configuration, just a snapshot of when I got it running.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I had forgotten to print out &lt;a href=&quot;https://www.printables.com/model/1218789-nitehawk-36-usb-adapter-mount-for-voron-din-clip&quot;&gt;a holder for the Nitehawk 36 USB&lt;/a&gt; but I had to get the printer up and running to print one.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/final_electronics.jpg&quot;&gt;
&lt;figcaption&gt;The electronics with cables cleaned up a little.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Overall it was surprisingly easy to reinstall all the electronics.
It was made easier by the move to umbilical and a single USB cable to the toolhead as it removed quite a bit of wiring:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/removed_wiring.jpg&quot;&gt;
&lt;figcaption&gt;Heap of things I removed from the printer when moving to umbilical and sensorless homing.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;One issue I had with the mod is that the cutouts for the Z motors were a bit large, with gaps where stray filament or heat can escape through.
I tried to cover them up by placing some foam tape around the motors:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/gaps_foam.jpg&quot;&gt;
&lt;figcaption&gt;The Z motor mounts have a gap between them and the electronics cover.
I tried to fill them in with foam tape from below.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-the-Jabberwocky&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-the-Jabberwocky&quot; class=&quot;heading-ref&quot;&gt;Why the &lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky&quot;&gt;Jabberwocky&lt;/a&gt;?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve been wanting to replace the Stealthburner toolhead a long time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
The cooling for PLA is quite bad.
&lt;/li&gt;
&lt;li&gt;
PLA has a tendency to clog (seems like a decently common problem with Rapido and Stealthburner).
&lt;/li&gt;
&lt;li&gt;
Resolving a clog when it happens is a pain in the ass.
&lt;/li&gt;
&lt;li&gt;
It lacks a filament sensor and a cutter (for multi-color).
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But what to choose?
There are quite a few interesting toolheads I considered:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/chirpy2605/voron/tree/main/V0/Dragon_Burner&quot;&gt;Dragon Burner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I use the &lt;a href=&quot;https://github.com/chirpy2605/voron/tree/main/V0/Dragon_Burner&quot;&gt;Dragon Burner&lt;/a&gt; in &lt;a href=&quot;/blog/2025/03/25/lets_build_a_voron_0&quot;&gt;my VORON 0&lt;/a&gt; and using the same toolhead is boring.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.armchairheavyindustries.com/docs/archetype&quot;&gt;Archetype&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A pretty fun toolhead and I was considering the &lt;a href=&quot;https://docs.armchairheavyindustries.com/docs/archetype/components/ducts/mjolnir&quot;&gt;Mjölnir&lt;/a&gt; version.
It does require you to flip your XY joints to hang upside down and I couldn’t find a filament sensor or filament cutter for it, so I ended up skipping it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Armchair-Heavy-Industries/Xol-Toolhead/tree/main&quot;&gt;XOL&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;XOL seems like a very well regarded and mature option with tons of support.
It boasts much better cooling for PLA, which is one of the main reasons I want to migrate away from the Stealthburner.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Armchair-Heavy-Industries/A4T&quot;&gt;A4T-toolhead&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A4T seems similar to XOL, while having even better cooling and a slightly simpler assembly.
It would also make use of the Dragon hotend I’ve got lying here, gathering dust.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky&quot;&gt;Jabberwocky&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An all-in-one toolhead solution with filament sensors and a filament cutter that seems to have some quality of life features I think I’d really enjoy:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Flip up Extruder. Probably an industry first, a tool-less easy to access toolhead design so that one can access the blade or the filament path for servicing and troubleshooting. This allows a user, in the event of hopefully a rare problem during a filament changing print the ability to access the filament path to clear it of issues and continue with a print job.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://github.com/TheKittieKatt/Information-Insights/tree/main/Beta%20Testing%20Results/Jabberwocky&quot;&gt;Jabberwocky Beta test&lt;/a&gt;, TheKittieKatt
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/Armchair-Heavy-Industries/A4T&quot;&gt;A4T-toolhead&lt;/a&gt; is interesting but the (supposedly) easier maintenance and multi-color
consistency of the &lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky&quot;&gt;Jabberwocky&lt;/a&gt; really appealed to me.&lt;/p&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update&lt;/div&gt;
&lt;p&gt;As I’m writing this I’ve already ordered parts for the A4T and I’ll try that out soon enough.
I just can’t help myself.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Building-the-Jabberwocky&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Building-the-Jabberwocky&quot; class=&quot;heading-ref&quot;&gt;Building the &lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky&quot;&gt;Jabberwocky&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Because &lt;em&gt;both&lt;/em&gt; of my printers were crapping out I had trouble getting some working parts for the build.
The print quality is not great and I need to first get the &lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky&quot;&gt;Jabberwocky&lt;/a&gt; up and running and then use it to reprint the bad parts.&lt;/p&gt;
&lt;p&gt;There’s also been quite a lot of revisions to the printed parts that might fix some of the issues I encountered.
I’m not too pleased with the colorscheme either so I’ll change that too.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/extruder_under_with_filament.jpg&quot;&gt;
&lt;figcaption&gt;The bottom of the extruder with a piece of filament sticking through.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I struggled a bit to get the filament to load/unload consistently by hand.
I rebuilt the toolhead but in the end I believe I just didn’t have enough grip on the filament to guide it past the gears down into bottom hole.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/fans_installed.jpg&quot;&gt;
&lt;figcaption&gt;The bottom part of the toolhead with fans installed.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/jw_back_no_conch.jpg&quot;&gt;
&lt;figcaption&gt;The back with &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt; but without the hotend installed.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/jw_front.jpg&quot;&gt;
&lt;figcaption&gt;The front but without the cover for the upper LED. (I forgot to print it before the printers went uncooperative.)
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;section id=&quot;Beacon-wiring&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Beacon-wiring&quot; class=&quot;heading-ref&quot;&gt;Beacon wiring&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/beacon.jpg&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://lab4450.com/product/original-beacon-3d-surface-scanner/&quot;&gt;Beacon&lt;/a&gt; is installed.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Most of the wiring came as-is except for the cable between the &lt;a href=&quot;https://lab4450.com/product/original-beacon-3d-surface-scanner/&quot;&gt;Beacon&lt;/a&gt; and the &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt;.
I got the &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt; side of the cable pre-made in the &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt; kit but I had to pin the &lt;a href=&quot;https://lab4450.com/product/original-beacon-3d-surface-scanner/&quot;&gt;Beacon&lt;/a&gt; side myself.&lt;/p&gt;
&lt;p&gt;The colors of the wires in cable were all over the place but there’s a description on the PCB of both the &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt; and &lt;a href=&quot;https://lab4450.com/product/original-beacon-3d-surface-scanner/&quot;&gt;Beacon&lt;/a&gt; so I just had to take care to match them.
I also referenced the &lt;a href=&quot;https://docs.ldomotors.com/en/Toolboard/nitehawk-36&quot;&gt;Nitehawk36 documentation&lt;/a&gt; and the &lt;a href=&quot;https://docs.beacon3d.com/usb_cables/&quot;&gt;Beacon documentation&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/beacon_to_nh36_wire.jpg&quot;&gt;
&lt;figcaption&gt;The wire between the &lt;a href=&quot;https://lab4450.com/product/original-beacon-3d-surface-scanner/&quot;&gt;Beacon&lt;/a&gt; and &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Cutter-installation-woes&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Cutter-installation-woes&quot; class=&quot;heading-ref&quot;&gt;Cutter installation woes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I had real difficulties installing the blade into the blade holder.
There was some filament in the hole (likely due to poor print tuning) and I managed to break the holder when I tried to install the blade:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/broken_cutter.jpg&quot;&gt;
&lt;figcaption&gt;I broke the blade holder when I tried to force in the blade.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/upper_with_broken_cutter.jpg&quot;&gt;
&lt;figcaption&gt;The lower part of the extruder where the blade will cut the filament.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;As I didn’t have a working printer when it broke I had to make it work without the filament cutter initially.
Luckily I didn’t break anything crucial…&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Software-setup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Software-setup&quot; class=&quot;heading-ref&quot;&gt;Software setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I had to make some software changes but luckily they were quite straightforward:&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;Use sensorless homing.&lt;/p&gt;
&lt;p&gt;I just followed the &lt;a href=&quot;https://docs.vorondesign.com/tuning/sensorless.html&quot;&gt;VORON documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup the &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk36-toolhead/&quot;&gt;Nitehawk36&lt;/a&gt; toolboard.&lt;/p&gt;
&lt;p&gt;LDO has &lt;a href=&quot;https://docs.ldomotors.com/en/Toolboard/nitehawk-36&quot;&gt;setup instructions&lt;/a&gt; and the Jabberwocky GitHub contains &lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky/blob/main/Sample_Configs/JW_NH36_config.cfg&quot;&gt;klipper settings&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup &lt;a href=&quot;https://lab4450.com/product/original-beacon-3d-surface-scanner/&quot;&gt;Beacon&lt;/a&gt; for Z offset and mesh calibration.&lt;/p&gt;
&lt;p&gt;Their &lt;a href=&quot;https://docs.beacon3d.com/quickstart/&quot;&gt;quickstart documentation&lt;/a&gt; was fast and easy.
I did not setup &lt;a href=&quot;https://docs.beacon3d.com/contact/&quot;&gt;Beacon Contact&lt;/a&gt;; maybe I’ll get to it one day.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Whats-next&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Whats-next&quot; class=&quot;heading-ref&quot;&gt;What’s next?&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/jw_mods/its_alive.jpg&quot;&gt;
&lt;figcaption&gt;The printer is finally printing again!
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;After months of not having a working 3D printer I’ve gotten renewed energy to play around with the printer again.
I’ve got some loose plans for some mods to make on this printer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Reprint the &lt;a href=&quot;https://github.com/kinematicdigit/Jabberwocky&quot;&gt;Jabberwocky&lt;/a&gt; and try to get the filament cutter up and running.
&lt;/li&gt;
&lt;li&gt;
Build and test the &lt;a href=&quot;https://github.com/Armchair-Heavy-Industries/A4T&quot;&gt;A4T-toolhead&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Install a nozzle scrubber.
&lt;/li&gt;
&lt;li&gt;
Build a &lt;a href=&quot;https://github.com/ArmoredTurtle/BoxTurtle&quot;&gt;Box Turtle&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;… Or maybe something else?
Who knows!&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Packing Neovim with Fennel</title><id>http://jonashietala.se/blog/2025/10/29/packing_neovim_with_fennel/index.html</id><updated>2026-04-27T15:24:47+00:00</updated><link href="https://www.jonashietala.se/blog/2025/10/29/packing_neovim_with_fennel" rel="alternate"/><published>2025-10-29T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/new_config_meme.jpg&quot;&gt;
&lt;figcaption&gt;I’ve got lots of stuff to do but I ended up rewriting my Neovim config instead.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;… anyone can do any amount of work, provided it isn’t the work he is supposed to be doing at that moment.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Robert Benchley, in Chips off the Old Benchley, 1949
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;My partner Veronica is amazing as she’ll listen to my bullshit and random whims (or at least, pretend to).
That’s a big benefit to having a blog: so I have an outlet for rambling about my weird projects and random fixations and spare Veronica’s sanity a little.&lt;/p&gt;
&lt;p&gt;I know that Veronica won’t be impressed by another Neovim config rewrite (even when done in Lisp!) so I’ll simply write a big blog post about it.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;This post will contain wild Lisp code and random Neovim references.
Please consult the &lt;a href=&quot;https://fennel-lang.org/reference&quot;&gt;Fennel safety manual&lt;/a&gt; and your nearest &lt;a href=&quot;https://neovim.io/doc/user/helphelp.html&quot;&gt;Neovim :help station&lt;/a&gt; for assistance.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;The-rewrite&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-rewrite&quot; class=&quot;heading-ref&quot;&gt;The rewrite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wanted to rewrite my Neovim configuration in &lt;a href=&quot;https://fennel-lang.org/&quot;&gt;Fennel&lt;/a&gt; (a Lisp that compiles to Lua) and while doing so I wanted to migrate from &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; to Neovim’s new built-in package manager &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This included bootstrapping &lt;a href=&quot;https://fennel-lang.org/&quot;&gt;Fennel&lt;/a&gt; compilation for Neovim; replicating missing features from &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; such as running build scripts and lazy loading; modernizing my LSP and treesitter config; and trying out some new interesting plugins.&lt;/p&gt;
&lt;p&gt;Please see &lt;a href=&quot;https://codeberg.org/treeman/nvim-conf&quot;&gt;my new Neovim config here&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;Why-Fennel&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-Fennel&quot; class=&quot;heading-ref&quot;&gt;Why Fennel?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Lua has been a fantastic boon to Neovim and it’s a significant improvement over Vimscript, yet I can’t help but raise an eyebrow when I hear people describe Lua as a &lt;em&gt;great&lt;/em&gt; language.
It’s definitely great at being a simple and fast embeddable language but the language itself leaves me wanting more.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fennel-lang.org/&quot;&gt;Fennel&lt;/a&gt; doesn’t solve all issues as some of Lua’s quirks bleeds through but it should make it a little bit nicer.
I particularly like the destructuring;
more functional programming constructs;
macros for convenient DSL;
and the amazing pipe operator.&lt;/p&gt;
&lt;p&gt;But the biggest reason is that I’m simply a bit bored and trying out new programming languages is fun.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-vimpack&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-vimpack&quot; class=&quot;heading-ref&quot;&gt;Why &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt;?&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t rewrite my config often. But when I do, I do it properly.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Ancient Neovim wisdom
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;Folke, maker of many popular plugins such as &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; and &lt;a href=&quot;https://github.com/folke/snacks.nvim&quot;&gt;snacks.nvim&lt;/a&gt;, recently had a ~5 month break from working on his plugins.
Of course, they continued to work and anyone working on open source projects can (and should) take a break whenever they want.&lt;/p&gt;
&lt;p&gt;But it exemplifies that core Neovim features will likely be better maintained than standalone plugins and should probably be preferred (if they provide the features you need).&lt;/p&gt;
&lt;p&gt;While &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;Neovim’s built-in plugin manager&lt;/a&gt; is a work in progress and still a bit too simplistic for my needs I wanted to try it out.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Structuring-the-config&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Structuring-the-config&quot; class=&quot;heading-ref&quot;&gt;Structuring the config&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you’ve got a small configuration having it all inside a single &lt;code&gt;init.lua&lt;/code&gt; is probably fine.
Somehow I’ve gathered almost 6k lines of Lua code under &lt;code&gt;~/.config/nvim&lt;/code&gt; so showing it all in one file isn’t that appealing.&lt;/p&gt;
&lt;p&gt;I first wanted to separate the configuration into a &lt;code&gt;core&lt;/code&gt;/&lt;code&gt;plugin&lt;/code&gt; split, where non-plugin configuration happens in &lt;code&gt;core&lt;/code&gt; and plugin configuration lives under &lt;code&gt;plugin&lt;/code&gt;.
However, to support lazy loading with a single call to &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack.add()&quot;&gt;vim.pack.add&lt;/a&gt; I decided to go back to letting the files under &lt;code&gt;plugin/&lt;/code&gt; return plugin specs, like &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; does for you.&lt;/p&gt;
&lt;p&gt;With Fennel support under &lt;code&gt;fnl/&lt;/code&gt; this is how my configuration is structured:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;init.lua                ; Minimal bootstrap to load Fennel files
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;fnl                     ; All Fennel source in the `fnl/` folder
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── config
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── init.fnl        ; Loaded by `init.lua` and loads the rest
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── colorscheme.fnl
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── keymaps.fnl
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── lsp.fnl         ; Config may reference plugins
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   └── ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── macros.fnl          ; Custom Fennel macros goes here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;└── plugins
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ├── init.fnl        ; Loads everything under `plugins/`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ├── appearance.fnl
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ├── coding.fnl
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    └── ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lua                     ; Lua stuff is still loaded transparently
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ftplugin
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;└── djot.lua            ; nvim-thyme doesn&apos;t load `ftplugin/`
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s not a perfect system as I’d ideally want the &lt;code&gt;plugins/&lt;/code&gt; to only add packages while I would configure the plugins in &lt;code&gt;config/&lt;/code&gt;.
But some plugins use lazy loading making it more convenient to do it together with the plugin spec.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Bootstrapping-Fennel&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Bootstrapping-Fennel&quot; class=&quot;heading-ref&quot;&gt;Bootstrapping Fennel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a handful of different plugins that allows you to easily write your Neovim config in Fennel.
I ended up choosing &lt;a href=&quot;https://github.com/aileot/nvim-thyme&quot;&gt;nvim-thyme&lt;/a&gt; because it’s fast (it hooks into &lt;code&gt;require&lt;/code&gt; and only compiles on-demand) and it allows you to mix Fennel and Lua source files.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aileot/nvim-thyme&quot;&gt;nvim-thyme&lt;/a&gt; compiles Fennel sources to Lua files and adds them to Neovim’s runtimepath.
This is how it allows you to seamlessly mix Fennel and Lua, where some parts may be written in Fennel and others in Lua.
On my machine they’re located at &lt;code&gt;~/.cache/nvim/thyme/compile/lua/&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aileot/nvim-thyme&quot;&gt;nvim-thyme&lt;/a&gt; contains installation instructions for &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; and it references a bootstrapping function to run &lt;code&gt;git&lt;/code&gt; to manually clone packages.
But we’re going to use &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt; and it makes the bootstrap a bit cleaner:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;init.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.pack.add({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Fennel environment and compiler.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/aileot/nvim-thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://git.sr.ht/~technomancy/fennel&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Gives us some pleasant fennel macros.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/aileot/nvim-laurel&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Enables lazy loading of plugins.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/BirdeeHub/lze&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}, { confirm &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt; })
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(I added &lt;a href=&quot;https://github.com/BirdeeHub/lze&quot;&gt;lze&lt;/a&gt; to my bootstrapping too as I’ll use it later &lt;a href=&quot;#Lazy-loading-with-lze&quot;&gt;when adding lazy loading support&lt;/a&gt;, it was simpler having it in the bootstrap.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aileot/nvim-thyme&quot;&gt;nvim-thyme&lt;/a&gt; also instructs us to override &lt;code&gt;require()&lt;/code&gt; calls (so it can compile on demand) and
to setup the cache path (where it’ll store the compiled Lua files):&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;init.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Override package loading so thyme can hook into `require` calls
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; and generate lua code if the required package is a fennel file.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(package.loaders, &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).loader(&lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Setup the compile cache path for thyme.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; thyme_cache_prefix &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.stdpath(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;cache&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/thyme/compiled&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.opt.rtp:prepend(thyme_cache_prefix)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we’re ready to write the rest of the config with Fennel!&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;init.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Load the rest of the config with transparent fennel support.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can continue with Fennel &lt;code&gt;fnl/config.fnl&lt;/code&gt; or &lt;code&gt;fnl/config/init.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;config&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Load all plugins
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:plugins&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Load the other config files
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:config.colorscheme&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:config.keymaps&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:config.lsp&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; etc...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Keep in mind that we don’t have to stay with Fennel all the time.&lt;br&gt;

&lt;code class=&quot;highlight fennel&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:config.lsp&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/code&gt; can load either &lt;code&gt;fnl/config/lsp.fnl&lt;/code&gt; or &lt;code&gt;lua/config/lsp.lua&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;There’s one last thing we should do to make the bootstrap complete: we should call &lt;code&gt;:ThymeCacheClear&lt;/code&gt; when &lt;code&gt;nvim-laurel&lt;/code&gt; or &lt;code&gt;nvim-thyme&lt;/code&gt; changes.
The recommended way is to use the &lt;a href=&quot;https://neovim.io/doc/user/pack.html#PackChanged&quot;&gt;PackChanged&lt;/a&gt; event, with something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;init.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.api.nvim_create_autocmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;PackChanged&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(event)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; name &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; event.data.spec.name
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; name &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;or&lt;/span&gt; name &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-laurel&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;ThymeCacheClear&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.api.nvim_create_augroup(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;init.lua&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { clear &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.pack.add(&lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But if we for example force an update for &lt;code&gt;nvim-laurel&lt;/code&gt; (by deleting it with 
&lt;code class=&quot;highlight lua&quot;&gt;vim.pack.del({&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-laurel&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;})&lt;/code&gt; and restart Neovim) we get this error:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Error in /home/tree/code/nvim-conf/init.lua..PackChanged Autocommands for &quot;*&quot;:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Lua callback: /home/tree/code/nvim-conf/init.lua:12: module &apos;thyme&apos; not found:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        no field package.preload[&apos;thyme&apos;]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        cache_loader: module &apos;thyme&apos; not found
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        cache_loader_lib: module &apos;thyme&apos; not found
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        no file &apos;./thyme.lua&apos;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is no order guarantee for the packages and so &lt;code&gt;PackChanged&lt;/code&gt; for &lt;code&gt;nvim-laurel&lt;/code&gt; may run before &lt;code&gt;thyme&lt;/code&gt; has been loaded.
I worked around this with a variable that I check after &lt;code&gt;vim.pack.add&lt;/code&gt;, which will guarantee that all packages have been added before we try to require a package:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;config&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; rebuild_thyme &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.api.nvim_create_autocmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;PackChanged&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(event)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; name &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; event.data.spec.name
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; name &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;or&lt;/span&gt; name &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-laurel&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;      rebuild_thyme &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.api.nvim_create_augroup(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;init.lua&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { clear &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.pack.add(&lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(package.loaders, &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).loader(&lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; thyme_cache_prefix &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.stdpath(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;cache&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/thyme/compiled&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.opt.rtp:prepend(thyme_cache_prefix)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup()
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Rebuild thyme cache after `vim.pack.add` to avoid dependency issues
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; and to make sure all packages are loaded.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; rebuild_thyme &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;ThymeCacheClear&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aileot/nvim-thyme&quot;&gt;nvim-thyme&lt;/a&gt; recommends 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;thyme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup()&lt;/code&gt; to be done in &lt;code&gt;VimEnter&lt;/code&gt; for speed reasons but I haven’t noticed any slowdown so I’ll just keep it in &lt;code&gt;init.lua&lt;/code&gt; for simplicity.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Building-a-convenient-plugin-management-system&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Building-a-convenient-plugin-management-system&quot; class=&quot;heading-ref&quot;&gt;Building a convenient plugin management system&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wanted to migrate to &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt; but it’s missing a few key features from &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
It can’t automatically require all files under a directory.
&lt;/li&gt;
&lt;li&gt;
There’s no lazy loading support.
&lt;/li&gt;
&lt;li&gt;
It can’t run build scripts (such as &lt;code&gt;make&lt;/code&gt; after install or update).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I could’ve given up and gone back to &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; but that just wouldn’t do.&lt;/p&gt;
&lt;section id=&quot;Source-pack-specs-from-files&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Source-pack-specs-from-files&quot; class=&quot;heading-ref&quot;&gt;Source pack specs from files&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I want to be able to create a file under &lt;code&gt;plugins/&lt;/code&gt;, have it return a &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack.Spec&quot;&gt;vim.pack.Spec&lt;/a&gt;, and have it automatically added. This is similar to the &lt;a href=&quot;https://lazy.folke.io/usage/structuring&quot;&gt;structured plugins&lt;/a&gt; approach of &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To build this I first list all files under &lt;code&gt;plugins/&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; List all files, with absolute paths.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;paths&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function macro&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;fn&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;stdpath&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;config&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;/fnl/plugins/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;fn&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;split&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;string escape&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This uses Fennel’s &lt;code&gt;-&amp;gt;&lt;/code&gt; &lt;a href=&quot;https://fennel-lang.org/reference#------and---threading-macros&quot;&gt;threading macro&lt;/a&gt;, Fennel’s version of the pipe operator.
It’s one of my favorite features of Elixir and was stoked to discover that Fennel has it too.
(Fennel actually has even more power with the &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;-?&amp;gt;&lt;/code&gt;, and &lt;code&gt;-?&amp;gt;&amp;gt;&lt;/code&gt; operators!)&lt;/p&gt;
&lt;p&gt;Now we need to loop through and transform the paths to relative paths and evaluate the files to get our specs.
(I’m using &lt;a href=&quot;https://fennel-lang.org/reference#accumulate-iterator-accumulation&quot;&gt;accumulate&lt;/a&gt; to explicitly build a list instead of &lt;a href=&quot;https://fennel-lang.org/reference#icollect-collect-table-comprehension-macros&quot;&gt;collect&lt;/a&gt; as we’ll soon expand on it):&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Make the paths relative to plugins and remove extension, e.g. &amp;quot;plugins/snacks&amp;quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;;; and require those packages to get our pack specs.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;specs&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function macro&quot;&gt;accumulate&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;abs_path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;ipairs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;               &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;abs_path&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;plugins&lt;/span&gt;/&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;^&lt;span class=&quot;operator&quot;&gt;.&lt;/span&gt;/&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;+&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;%.fnl$&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;not=&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;plugins/init&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;mod_res&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;mod_res&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can populate &lt;code&gt;specs&lt;/code&gt; from files under &lt;code&gt;plugins/&lt;/code&gt;, for example like this that returns a single spec:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;misc.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/romainl/vim-cool&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Fennel’s table syntax felt a bit weird for me at first.

&lt;code class=&quot;highlight fennel&quot;&gt;&lt;span class=&quot;string&quot;&gt;:src&lt;/span&gt;
&lt;/code&gt; is the same as 
&lt;code class=&quot;highlight fennel&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;src&amp;quot;&lt;/span&gt;
&lt;/code&gt; and the above code translates to this Lua:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; { src &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/romainl/vim-cool&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;But I also want to be able to return multiple specs:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;deps.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/nvim-lua/popup.nvim&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/nvim-lua/plenary.nvim&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To support this we can match on the return value to see if it’s a list, and then loop and insert each spec in the list, otherwise we do as before:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;specs&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function macro&quot;&gt;accumulate&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;abs_path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;ipairs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;               &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;abs_path&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;plugins&lt;/span&gt;/&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;^&lt;span class=&quot;operator&quot;&gt;.&lt;/span&gt;/&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;+&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;%.fnl$&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;not=&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;plugins/init&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;mod_res&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;                       &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;mod_res&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;                         ;; Flatten return if we return a list of specs.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;                         &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;specs&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;                         &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword repeat&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;ipairs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;mod_res&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;                           &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;                         ;; Can return a string or a single spec.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;                         &lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;                         &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;mod_res&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now all that’s left is to call &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack.add()&quot;&gt;vim.pack.add&lt;/a&gt; with our list of specs and our plugins are now automatically added from files under &lt;code&gt;plugins/&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;specs&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:confirm&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Lazy-loading-with-lze&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Lazy-loading-with-lze&quot; class=&quot;heading-ref&quot;&gt;Lazy loading with &lt;a href=&quot;https://github.com/BirdeeHub/lze&quot;&gt;lze&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/BirdeeHub/lze&quot;&gt;lze&lt;/a&gt; is a nice and simple plugin to add lazy-loading to &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We’ve already added it as a dependency in our &lt;code&gt;init.lua&lt;/code&gt; so all we need to do is modify the &lt;code&gt;load&lt;/code&gt; parameter to &lt;code&gt;vim.pack.add&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Override loader when adding to let lze handle lazy loading
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;;; when specified via the `data` attribute.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;specs&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:load&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                             &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;or&lt;/span&gt; p&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                             &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;set&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt; p&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                             &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;lze&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:lze&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                             &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;lze&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;label&quot;&gt;:confirm&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can specify lazy loading via the &lt;code&gt;data&lt;/code&gt; parameter in our specs:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;misc.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/romainl/vim-cool&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:data&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:event&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;BufReadPost&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;BufNewFile&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It relies on wrapping configuration under &lt;code&gt;data&lt;/code&gt; but that’s annoying, so let’s simplify things a little.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Simplified-specifications&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Simplified-specifications&quot; class=&quot;heading-ref&quot;&gt;Simplified specifications&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The idea here is to transform the specs before we call &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack.add()&quot;&gt;vim.pack.add&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We can do it easily when we collect our specs by calling the &lt;code&gt;transform_spec&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;specs&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function macro&quot;&gt;accumulate&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;abs_path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;ipairs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;               &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;abs_path&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;plugins&lt;/span&gt;/&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;^&lt;span class=&quot;operator&quot;&gt;.&lt;/span&gt;/&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;+&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;%.fnl$&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;not=&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;plugins/init&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;mod_res&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;mod_res&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;specs&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword repeat&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;ipairs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;mod_res&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;                           &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;transform_spec&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;                         &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;transform_spec&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;mod_res&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                       &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;variable parameter&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I want &lt;code&gt;transform_spec&lt;/code&gt; to transform this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/romainl/vim-cool&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:event&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;BufReadPost&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;BufNewFile&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Into this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/romainl/vim-cool&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:data&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:event&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;BufReadPost&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;BufNewFile&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By storing keys other than &lt;code&gt;src&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;version&lt;/code&gt; under a &lt;code&gt;data&lt;/code&gt; table.
This is what I came up with:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;transform_spec&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string&quot;&gt;&amp;quot;Transform a vim.pack spec and move lze arguments into `data`&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;      ;; Split keys to vim.pack and rest into `data`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pack_args&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;data_args&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword repeat&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;pairs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;list_contains&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:version&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;tset&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack_args&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;tset&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;data_args&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;set&lt;/span&gt; pack_args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;data_args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;variable parameter&quot;&gt;pack_args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;    ;; Bare strings are valid vim.pack specs too.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;variable&quot;&gt;other&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable parameter&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another quality of life feature I’d like is to make it simpler to call &lt;code&gt;setup&lt;/code&gt; functions.
&lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; again does this well and it’s pretty convenient.&lt;/p&gt;
&lt;p&gt;For example, this is how it looks like with &lt;a href=&quot;https://github.com/BirdeeHub/lze&quot;&gt;lze&lt;/a&gt; to add an &lt;code&gt;after&lt;/code&gt; hook and call a &lt;code&gt;setup&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/A7Lavinraj/fyler.nvim&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:on_require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:fyler&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;fyler&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:fyler&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;fyler&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:icon_provider&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim_web_devicons&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        &lt;span class=&quot;label&quot;&gt;:default_explorer&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What if we could instead do:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/A7Lavinraj/fyler.nvim&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:on_require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:fyler&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:setup&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:icon_provider&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim_web_devicons&amp;quot;&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:default_explorer&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But this is just data and we can transform the second case to the first one fairly easily.
In the &lt;code&gt;transform_spec&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;transform_spec&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string&quot;&gt;&amp;quot;Transform a vim.pack spec and move lze arguments into `data`&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;   and create an `after` hook if `setup` is specified.&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;      ;; Split keys to vim.pack and rest into `data`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pack_args&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;data_args&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword repeat&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;pairs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;list_contains&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:version&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;tset&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack_args&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;tset&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;data_args&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;        ;; Call `setup()` functions if needed.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;setup&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pkg&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;on_require&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;pkg&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;setup&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;        ;; Load user specified `after` if it exists.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;after&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;set&lt;/span&gt; data_args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;set&lt;/span&gt; pack_args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;data_args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;variable parameter&quot;&gt;pack_args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;    ;; Bare strings are valid vim.pack specs too.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;variable&quot;&gt;other&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable parameter&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How to figure out the package name to require (since it may differ from the path)?
&lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; has a bunch of rules to try to figure this out automatically but I chose to be explicit.
&lt;a href=&quot;https://github.com/BirdeeHub/lze&quot;&gt;lze&lt;/a&gt; uses the &lt;code&gt;on_require&lt;/code&gt; argument so it can load on a require call (on 
&lt;code class=&quot;highlight fennel&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:fyler&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/code&gt; for example), which seems like a good idea to reuse.&lt;/p&gt;
&lt;p&gt;And just to prevent me from making mistakes, I added a sanity check:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; `:setup` needs to know what package to require,
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;;; therefore we use `:on_require`
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;and&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;not&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;on_require&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;`&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;setup` specified without `on_require`&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt; &amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;             &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;inspect&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;  ;; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Build-scripts-via-PackChanged-events&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Build-scripts-via-PackChanged-events&quot; class=&quot;heading-ref&quot;&gt;Build scripts via PackChanged events&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There’s one last feature I really want from &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; and that’s to automatically run build scripts after a package is installed or updated.&lt;/p&gt;
&lt;p&gt;I basically want to specify this in my specs:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/eraserhd/parinfer-rust&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;cargo&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;build&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;--release&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again, we’ll rely on &lt;a href=&quot;https://neovim.io/doc/user/pack.html#PackChanged&quot;&gt;PackChanged&lt;/a&gt; for this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Before `vim.pack.add` to capture changes.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;augroup!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:plugin_init&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;au!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:PackChanged&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack_changed&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above code uses macros from &lt;a href=&quot;https://github.com/aileot/nvim-laurel&quot;&gt;nvim-laurel&lt;/a&gt; to define an autocommand that calls the &lt;code&gt;pack_changed&lt;/code&gt; function.
That function will then run &lt;code&gt;pack_changed&lt;/code&gt; when the package is updated or installed:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack_changed&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;list_contains&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;:update&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:install&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; event&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;execute_build&lt;/span&gt; event&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;  ;; Return false to not remove the autocommand.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;execute_build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;   ;; `?.` will prevent crashing if any field is nil.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function macro&quot;&gt;?.&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:spec&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:data&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:build&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;run_build_script&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To run the scripts I use &lt;a href=&quot;https://neovim.io/doc/user/lua.html#vim.system()&quot;&gt;vim.system&lt;/a&gt; with some simple printing:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;run_build_script&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;path&lt;/span&gt; pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;notify&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Run `&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;inspect&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;` for &amp;quot;&lt;/span&gt; pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;              &lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;log&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;levels&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:cwd&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;              &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;exit_obj&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;not=&lt;/span&gt; exit_obj&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;                  ;; If I use `vim.notify` it errors with:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;                  ;; vim/_editor.lua:0: E5560: nvim_echo must not be called in a fast event context
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;                  ;; Simply printing is fine I guess, it doesn&amp;#39;t have to be the prettiest solution.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;inspect&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;failed in&amp;quot;&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;path&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;inspect&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;exit_obj&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will now allow us to run build scripts like &lt;code&gt;cargo build --release&lt;/code&gt; or &lt;code&gt;make&lt;/code&gt; after a package is installed or updated.
It’s a bit too basic as there’s no visible progress bar for long running builds (Rust, I’m looking at you!) and it doesn’t handle build errors that well but it works well enough I guess.&lt;/p&gt;
&lt;p&gt;But what about user commands or requiring a package? For example with &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; you’d want to run &lt;code&gt;:TSUpdate&lt;/code&gt; after an update,
something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/nvim-treesitter/nvim-treesitter&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:version&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:main&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:build&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;TSUpdate&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s try it by allowing functions in the &lt;code&gt;build&lt;/code&gt; parameter (and bare strings because why not):&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;execute_build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function macro&quot;&gt;?.&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:spec&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:data&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:build&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;      ;; We can specify either &amp;quot;make&amp;quot; or [&amp;quot;make&amp;quot;]
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;string&quot;&gt;&amp;quot;string&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;run_build_script&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;      &lt;span class=&quot;string&quot;&gt;&amp;quot;table&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;run_build_script&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;      ;; Run a callback instead.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;string&quot;&gt;&amp;quot;function&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;call_build_cb&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;call_build_cb&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;notify&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Call build hook for &amp;quot;&lt;/span&gt; pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;log&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;levels&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we run this though it doesn’t work:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Error in /home/tree/code/nvim-conf/init.lua..PackChanged Autocommands for &quot;*&quot;:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Lua callback: vim/_editor.lua:0: /home/tree/code/nvim-conf/init.lua..PackChanged Autocommands for &quot;*&quot;..script nvim_exec2() called
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;at PackChanged Autocommands for &quot;*&quot;:0, line 1: Vim:E492: Not an editor command: TSUpdate
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The problem is that &lt;code&gt;PackChanged&lt;/code&gt; is run before the pack is loaded.
Maybe we could work around this by calling &lt;a href=&quot;https://neovim.io/doc/user/repeat.html#%3Apackadd&quot;&gt;packadd&lt;/a&gt; ourselves but that would shortcut lazy loading.
In this instance we’d like to run &lt;code&gt;TSUpdate&lt;/code&gt; after the pack is loaded but only if it’s been updated or installed so we don’t run it after every restart.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Yeah I know that &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; shouldn’t be lazy loaded anyway so it might be a bad example.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;What I did was introduce an &lt;code&gt;after_build&lt;/code&gt; parameter to the spec that’s run after load if a &lt;code&gt;PackChanged&lt;/code&gt; event was seen before:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/nvim-treesitter/nvim-treesitter&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:version&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:main&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt; &lt;span class=&quot;label&quot;&gt;:after_build&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;TSUpdate&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then in &lt;code&gt;plugins/init.fnl&lt;/code&gt; I use a local variable &lt;code&gt;packs_changed&lt;/code&gt; that’s updated on &lt;a href=&quot;https://neovim.io/doc/user/pack.html#PackChanged&quot;&gt;PackChanged&lt;/a&gt; like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Capture packs that are updated or installed.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;g!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:packs_changed&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;set_pack_changed&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;  ;; Maybe there&amp;#39;s an easier way of updating a table global...?
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;packs&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;packs_changed&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;tset&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;packs&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;g!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:packs_changed&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;packs&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack_changed&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;list_contains&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;:update&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:install&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt; event&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pack&lt;/span&gt; event&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;set_pack_changed&lt;/span&gt; pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;execute_build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we’ll call &lt;code&gt;after_build&lt;/code&gt; from the &lt;code&gt;after&lt;/code&gt; hook we setup before:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;transform_spec&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;spec&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;      ;; Split keys to vim.pack and rest into `data`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;      ;; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pack_changed_event&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;packs_changed&lt;/span&gt; args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;set_pack_changed&lt;/span&gt; args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;setup&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pkg&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;on_require&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;pkg&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;setup&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment&quot;&gt;        ;; Run `after_build` scripts if a `PackChanged` event
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;        ;; was run with `install` or `update`.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;and&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;after_build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack_changed_event&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;after_build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;after&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;set&lt;/span&gt; data_args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;set&lt;/span&gt; pack_args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;data_args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;variable parameter&quot;&gt;pack_args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable&quot;&gt;other&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable parameter&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this we can finally specify build actions such as these:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:build&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;make&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;cargo&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;build&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;--release&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:after_build&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;TSUpdate&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;While the build system mostly works, once in a while it’ll break and fail to run the build scripts.
Maybe there was a weird build error or something.
For these cases I have a 
&lt;code class=&quot;highlight fennel&quot;&gt;&lt;span class=&quot;string&quot;&gt;:BuildPacks&lt;/span&gt;
&lt;/code&gt; user command that runs &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;after_build&lt;/code&gt; for all packs like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;plugins&amp;#x2F;init.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;command!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:BuildPacks&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword repeat&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;ipairs&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;              &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;execute_build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;              &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;after_build&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function macro&quot;&gt;?.&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:spec&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:data&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:after_build&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;              &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;after_build&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;execute_after_build&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;after_build&lt;/span&gt; pack&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I really hope that proper build script support will land in core Neovim one day so I can rid myself of my crappy implementation.
It makes me feel icky.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Some-Fennel-examples&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Some-Fennel-examples&quot; class=&quot;heading-ref&quot;&gt;Some Fennel examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You’ve already seen how Fennel code looks like but what about configuration with Fennel?
One of the negative things of moving my configuration from Vimscript to Lua was that simple things such as settings options or simple keymaps is more verbose.&lt;/p&gt;
&lt;p&gt;So how does Fennel compare for the simpler, more declarative stuff?&lt;/p&gt;
&lt;section id=&quot;Options&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Options&quot; class=&quot;heading-ref&quot;&gt;Options&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;vimscript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight vim&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function viml&quot;&gt;set&lt;/span&gt; relativenumber
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function viml&quot;&gt;set&lt;/span&gt; clipboard^=unnamed,unnamedplus
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function viml&quot;&gt;set&lt;/span&gt; backupdir&lt;span class=&quot;storage function viml&quot;&gt;=~&lt;/span&gt;&lt;span class=&quot;string regexp viml&quot;&gt;/.config/&lt;/span&gt;nvim/backup
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function viml&quot;&gt;let&lt;/span&gt; mapleader=&lt;span class=&quot;string quoted double viml&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.opt.relativenumber &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.opt.clipboard:append({ &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;unnamed&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;unnamedplus&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.opt.backupdir &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.expand(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;~/.config/nvim/backup&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.g.mapleader &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted other multiline lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;punctuation definition string end lua&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;set!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:relativenumber&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;set!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:clipboard&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;unnamed&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;unnamedplus&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;set!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:backupdir&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;fn&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;expand&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;~/.config/nvim/backup&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;g!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:mapleader&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/aileot/nvim-laurel&quot;&gt;nvim-laurel&lt;/a&gt; macros I think Fennel is decent.
Slightly better than Lua but not as convenient as Vimscript.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Keymaps&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Keymaps&quot; class=&quot;heading-ref&quot;&gt;Keymaps&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; map &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.keymap.set
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;localleader&amp;gt;D&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, vim.lsp.buf.declaration,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { silent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, buffer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; buffer, desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Declaration&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;leader&amp;gt;ep&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;() find_org_file(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;projects&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Org projects&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;]t&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;trouble&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).next({ skip_groups &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, jump &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Trouble next&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  silent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;bmap!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:n&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&amp;lt;localleader&amp;gt;D&amp;quot;&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;declaration&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:silent&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:desc&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Declaration&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;map!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:n&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&amp;lt;leader&amp;gt;ep&amp;quot;&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;find_org_file&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;projects&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:desc&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Org projects&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;map!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:n&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;t&amp;quot;&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;trouble&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:trouble&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;trouble&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:skip_groups&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:jump&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:silent&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:desc&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Trouble next&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not a huge difference to be honest.
I like the &lt;code&gt;#(do_the_thing)&lt;/code&gt; shorthand for anonymous functions fennel has.
Having to (sometimes) split up &lt;code&gt;require&lt;/code&gt; and method calls on separate lines in Fennel is annoying.&lt;/p&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update &lt;span class=&quot;date&quot;&gt;2025-10-29&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/neovim/comments/1oj1unx/packing_neovim_with_fennel/nm04511/&quot;&gt;A comment on Reddit&lt;/a&gt; pointed out that you can simplify &lt;code&gt;require&lt;/code&gt; and method calls with a macro:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string&quot;&gt;&amp;quot;Call a function on a module&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;assert-compile&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;sym?&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;expected module name&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;assert-compile&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;sym?&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;expected function name&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation special&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;tostring&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;tostring&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;variable builtin&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then use it like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;map!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:n&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;t&amp;quot;&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;trouble&lt;/span&gt; &lt;span class=&quot;function builtin&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:skip_groups&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:jump&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:silent&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:desc&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Trouble next&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Overriding-highlight-groups&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Overriding-highlight-groups&quot; class=&quot;heading-ref&quot;&gt;Overriding highlight groups&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One example that was a big step up with Fennel is overriding highlight groups.
I’m using &lt;a href=&quot;https://github.com/savq/melange-nvim&quot;&gt;melange&lt;/a&gt; which is a fantastic and underrated color scheme but I’ve collected a fair bit of overrides for it.&lt;/p&gt;
&lt;p&gt;In Lua you use &lt;a href=&quot;https://neovim.io/doc/user/api.html#nvim_set_hl()&quot;&gt;nvim_set_hl&lt;/a&gt; to add an override, for example like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.api.nvim_set_hl(&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@symbol.elixir&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { link &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@label&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you do this 100 times this is &lt;em&gt;annoying&lt;/em&gt; so I made an override table to accomplish the job:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; overrides &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { name &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@symbol.elixir&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, val &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { link &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@label&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { name &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@string.special.symbol.elixir&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, val &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { link &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@label&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { name &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@constant.elixir&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, val &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { link &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Constant&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; And around 100 other overrides...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;for&lt;/span&gt; _, v &lt;span class=&quot;keyword control lua&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;pairs&lt;/span&gt;(overrides) &lt;span class=&quot;keyword control lua&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  vim.api.nvim_set_hl(&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;, v.name, v.val)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In &lt;a href=&quot;https://fennel-lang.org/&quot;&gt;Fennel&lt;/a&gt; with the &lt;a href=&quot;https://github.com/aileot/nvim-laurel/blob/main/docs/reference.md#highlight&quot;&gt;hi!&lt;/a&gt; macro this all becomes as simple as:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;hi!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;symbol.elixir&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:link&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;label&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;hi!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;string.special.symbol.elixir&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:link&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;label&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;hi!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;constant.elixir&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:link&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Constant&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Autocommands&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Autocommands&quot; class=&quot;heading-ref&quot;&gt;Autocommands&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here are some autocommands to enable &lt;a href=&quot;https://neovim.io/doc/user/options.html#&apos;cursorline&apos;&quot;&gt;cursorline&lt;/a&gt; only in the currently active window (while skipping buffers such as the dashboard):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; augroup(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;my-autocmds&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { clear &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;autocmd({ &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;VimEnter&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;WinEnter&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufWinEnter&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; group,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(x)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.len&lt;/span&gt;(x.file) &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      vim.opt_local.cursorline &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;autocmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;WinLeave&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; group,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    vim.opt_local.cursorline &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;augroup!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:my-autocmds&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;au!&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;:VimEnter&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:WinEnter&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:BufWinEnter&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;               &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;len&lt;/span&gt; $1&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                    &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;let! &lt;span class=&quot;string&quot;&gt;:&lt;span class=&quot;module&quot;&gt;opt_local&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:cursorline&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                  &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;au!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:WinLeave&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                            &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;let! &lt;span class=&quot;string&quot;&gt;:&lt;span class=&quot;module&quot;&gt;opt_local&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:cursorline&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                            &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Plugin-specs&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Plugin-specs&quot; class=&quot;heading-ref&quot;&gt;Plugin specs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One thing I like more in Lua compared to Fennel is how readable tables are.
The Fennel formatter &lt;a href=&quot;https://git.sr.ht/~technomancy/fnlfmt&quot;&gt;fnlfmt&lt;/a&gt; might be partly to blame as it has a tendency to use very little whitespace. Regardless, I prefer this Lua code:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/stevearc/conform.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { src &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/mason-org/mason.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, dep_of &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;mason-lspconfig.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { src &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/neovim/nvim-lspconfig&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, dep_of &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;mason-lspconfig.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/mason-org/mason-lspconfig.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    src &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/nvim-treesitter/nvim-treesitter&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    version &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;main&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    after &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TSUpdate&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Over this corresponding Fennel code:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/stevearc/conform.nvim&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/mason-org/mason.nvim&amp;quot;&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:dep_of&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:mason-lspconfig.nvim&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/neovim/nvim-lspconfig&amp;quot;&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:dep_of&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:mason-lspconfig.nvim&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/mason-org/mason-lspconfig.nvim&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/nvim-treesitter/nvim-treesitter&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;label&quot;&gt;:version&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:main&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;label&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;TSUpdate&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To me the Lua code is for some reason easier to read.&lt;/p&gt;
&lt;p&gt;Similarly I don’t have a problem with this &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; spec:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;folke/snacks.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  priority &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1000&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  lazy &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  opts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    indent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      indent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        enabled &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        char &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;┆&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      scope &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        enabled &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        only_current &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    scroll &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      animate &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        duration &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { step &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;15&lt;/span&gt;, total &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;150&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    explorer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {},
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But with this new Fennel spec I use—even though it’s simpler in some ways—it’s harder for me to quickly see what table the keys belong to:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:src&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt;//github.com/folke/snacks.nvim&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:on_require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:snacks&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:lazy&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;label&quot;&gt;:setup&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:indent&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:indent&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:enabled&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:char&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;┆&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                  &lt;span class=&quot;label&quot;&gt;:scope&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:enabled&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:only_current&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;label&quot;&gt;:scroll&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:animate&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:duration&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:step&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:total&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;label&quot;&gt;:explorer&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Maybe it’s something you’ll get used to?&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;A big plus with the setup I use is that I can mix Funnel and Lua, so if I get tired of the &lt;a href=&quot;https://fennel-lang.org/&quot;&gt;Fennel&lt;/a&gt; tables I could keep them in Lua and have the more “codey” parts in Fennel.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Notable-plugin-updates&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Notable-plugin-updates&quot; class=&quot;heading-ref&quot;&gt;Notable plugin updates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Neovim is moving quickly and I’ve had a bit of catching up to do in the plugin department.
I won’t bore you with an exhaustive list; just a few highlights.&lt;/p&gt;
&lt;section id=&quot;Native-undotree&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Native-undotree&quot; class=&quot;heading-ref&quot;&gt;Native undotree&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve been using &lt;a href=&quot;https://github.com/jiaoshijie/undotree&quot;&gt;undotree&lt;/a&gt; a long time and it’s excellent.
&lt;a href=&quot;https://neovim.io/doc/user/plugins.html#_builtin-plugin:-undotree&quot;&gt;This feature&lt;/a&gt; was &lt;a href=&quot;https://github.com/neovim/neovim/pull/35627&quot;&gt;recently merged into Neovim&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; It&amp;#39;s optional so we need to use packadd to activate the plugin:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;packadd nvim.undotree&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Then we can add a keymap to open it:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;map!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:n&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&amp;lt;leader&amp;gt;u&amp;quot;&lt;/span&gt; &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:undotree&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:open&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:command&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;topleft 30vnew&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Simplified-LSP-config&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Simplified-LSP-config&quot; class=&quot;heading-ref&quot;&gt;Simplified LSP config&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Neovim routinely gets shit on for LSPs being so hard to setup.
Yes, it could probably be easier but Neovim has recently made some changes to streamline LSP configuration and it’s not nearly as involved as it used to be.&lt;/p&gt;
&lt;p&gt;Here’s how my base config looks like:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;config&amp;#x2F;lsp.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword import&quot;&gt;require-macros&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:macros&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Convenient way of installing LSPs and other tools.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;mason&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:mason&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;mason&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Convenient way of automatically enabling LSPs installed via Mason.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;mason-lspconfig&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:mason-lspconfig&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;mason-lspconfig&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:automatic_enable&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Show diagnostics as virtual lines on the current line.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;;; It&amp;#39;s pretty cool actually, you should try it out.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;diagnostic&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:virtual_text&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        &lt;span class=&quot;label&quot;&gt;:severity_sort&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        &lt;span class=&quot;label&quot;&gt;:virtual_lines&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:current_line&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; I like inlay hints.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;lsp&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;inlay_hint&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;augroup!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:my-lsps&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;au!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:LspAttach&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;               &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;snacks&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:snacks&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;bmap!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:n&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&amp;lt;localleader&amp;gt;D&amp;quot;&lt;/span&gt; snacks&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;picker&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;lsp_declarations&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:silent&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:desc&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Declaration&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;bmap!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:n&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;&amp;lt;localleader&amp;gt;l&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        &lt;span class=&quot;keyword function&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;diagnostic&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;open_float&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:focusable&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:silent&lt;/span&gt; &lt;span class=&quot;boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;:desc&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Diagnostics&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;                ;; etc
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I also use &lt;a href=&quot;https://github.com/neovim/nvim-lspconfig&quot;&gt;nvim-lspconfig&lt;/a&gt; but it doesn’t do anything magical (anymore).
It’s basically a &lt;a href=&quot;https://github.com/neovim/nvim-lspconfig/tree/master/lsp&quot;&gt;collection of LSP configs&lt;/a&gt;, so I don’t have to fill my config with things like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fennel&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;lsp&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;expert&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;:cmd&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;expert&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;label&quot;&gt;:root_markers&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;mix.exs&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;.git&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;label&quot;&gt;:filetypes&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;elixir&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;eelixir&amp;quot;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;heex&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;lsp&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;expert&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you don’t want to change the keymaps (Neovim comes with defaults that I personally dislike) or customize specific LSPs then there’s not that much left.
&lt;a href=&quot;https://github.com/mason-org/mason.nvim&quot;&gt;Mason&lt;/a&gt; is also totally optional and if you want to manage your LSPs outside of Neovim you can totally do that.
The only thing missing is autocomplete, which &lt;a href=&quot;https://github.com/Saghen/blink.cmp&quot;&gt;blink.cmp&lt;/a&gt; provides out of the box.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Automatically-install-and-enable-treesitter-grammars&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Automatically-install-and-enable-treesitter-grammars&quot; class=&quot;heading-ref&quot;&gt;Automatically install and enable treesitter grammars&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another thing that has changed since my last config overhaul is &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; being rewritten and is now a much simpler plugin. The new version lives on the &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter/tree/main&quot;&gt;main branch&lt;/a&gt; and the old archived one on &lt;code&gt;master&lt;/code&gt; and it contains a bunch of breaking changes.&lt;/p&gt;
&lt;p&gt;For example, it no longer supports installing and activating grammars automatically.
I think I saw a plugin for that somewhere but here’s some Fennel code that sets it up:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fnl&amp;#x2F;config&amp;#x2F;treesitter.fnl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fennel&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword import&quot;&gt;require-macros&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:macros&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;nvim-treesitter&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function builtin&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:nvim-treesitter&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;;; Ignore auto install for these filetypes:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;ignored_ft&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;augroup!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:treesitter&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;au!&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:FileType&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;               &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;bufnr&lt;/span&gt; args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;ft&lt;/span&gt; args&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable member&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;                 ;; Auto install grammars unless explicitly ignored.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                 &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;list_contains&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;ignored_ft&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;ft&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                   &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;nvim-treesitter&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;ft&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;:await&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                      &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword function&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;                        ;; Enable highlight only if there&amp;#39;s an installed grammar.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;installed&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;nvim-treesitter&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;get_installed&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword conditional&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;nvim_buf_is_loaded&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;bufnr&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                   &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;list_contains&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;installed&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;ft&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                          &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;module&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;treesitter&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;function call&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;variable parameter&quot;&gt;bufnr&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you use &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter-textobjects/tree/main&quot;&gt;nvim-treesitter-textobjects&lt;/a&gt; (which you should) remember to migrate to the &lt;code&gt;main&lt;/code&gt; branch there too.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Some-new-fun-plugins&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Some-new-fun-plugins&quot; class=&quot;heading-ref&quot;&gt;Some new fun plugins&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/A7Lavinraj/fyler.nvim&quot;&gt;fyler.nvim&lt;/a&gt;, edit a file explorer like a buffer&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/stevearc/oil.nvim&quot;&gt;oil.nvim&lt;/a&gt; is a great plugin that allows you to manage files by simply editing text.
&lt;a href=&quot;https://github.com/A7Lavinraj/fyler.nvim&quot;&gt;fyler.nvim&lt;/a&gt; takes it to the next level by combining it with a tree-style file explorer.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;You may wonder, how in the world does it work?&lt;/p&gt;
&lt;p&gt;It’s both smart and simple: the plugins use unique identifiers together with Neovim’s conceal feature to hide them.
If you go into an &lt;a href=&quot;https://github.com/stevearc/oil.nvim&quot;&gt;oil.nvim&lt;/a&gt; or &lt;a href=&quot;https://github.com/A7Lavinraj/fyler.nvim&quot;&gt;fyler.nvim&lt;/a&gt; buffer and remove the conceal with &lt;code&gt;:set conceallevel=0&lt;/code&gt; you can see this for yourself:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;/00008 drafts
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  /00037 my_first_homelab_rack.dj
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  /00038 nvim_fennel_pack_rewrite.dj
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  /00041 leftie.dj
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So if I would rename &lt;code&gt;leftie&lt;/code&gt; to &lt;code&gt;rightie&lt;/code&gt; in the buffer above and save:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;/00041 rightie.dj
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The plugin would see the &lt;code&gt;/00041&lt;/code&gt; identifier and recognize the rename.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Saghen/blink.cmp&quot;&gt;blink.cmp&lt;/a&gt;, faster autocomplete&lt;/p&gt;
&lt;p&gt;I’ve been using &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt; as my completion plugin but I migrated to &lt;a href=&quot;https://github.com/Saghen/blink.cmp&quot;&gt;blink.cmp&lt;/a&gt; as it’s faster and more actively maintained.
It’s too bad that it broke &lt;a href=&quot;/blog/2024/05/26/autocomplete_with_nvim-cmp/&quot;&gt;my custom nvim-cmp source for my blog&lt;/a&gt; but it wasn’t too hard to migrate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/folke/snacks.nvim&quot;&gt;snacks.nvim&lt;/a&gt;, a better picker&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; has been a solid picker but it’s no longer actively developed and the &lt;a href=&quot;https://github.com/folke/snacks.nvim&quot;&gt;snacks.nvim&lt;/a&gt;
is the replacement I settled on.&lt;/p&gt;
&lt;p&gt;I tried &lt;a href=&quot;https://github.com/dmtrKovalenko/fff.nvim&quot;&gt;fff.nvim&lt;/a&gt; for file picking but surprisingly it felt really slow compared to &lt;a href=&quot;https://github.com/folke/snacks.nvim&quot;&gt;snacks.nvim&lt;/a&gt;.
&lt;a href=&quot;https://github.com/ibhagwan/fzf-lua&quot;&gt;fzf-lua&lt;/a&gt; is another great alternative that I haven’t given enough attention to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/MagicDuck/grug-far.nvim&quot;&gt;grug-far.nvim&lt;/a&gt;, global query replace&lt;/p&gt;
&lt;p&gt;I’ve been happy with Neovim’s regular &lt;code&gt;%s/foo/bar&lt;/code&gt; for single files (aided by &lt;a href=&quot;https://github.com/roobert/search-replace.nvim&quot;&gt;search-replace.nvim&lt;/a&gt; for easy population).
But query replace in multiple files has always felt lacking.
I used to use &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; to populate the quickfix window and then use &lt;a href=&quot;https://github.com/gabrielpoca/replacer.nvim&quot;&gt;replacer.nvim&lt;/a&gt; to make it editable, updating multiple files.&lt;/p&gt;
&lt;p&gt;It worked but was a bit annoying so now I’m trying &lt;a href=&quot;https://github.com/MagicDuck/grug-far.nvim&quot;&gt;grug-far.nvim&lt;/a&gt; as a more “over engineered” solution.
I haven’t used it that long to say for sure but I’m hopeful.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Yes, LSP backed rename exists and it’s great. But sometimes you want to operate on text.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Ending-thougths&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Ending-thougths&quot; class=&quot;heading-ref&quot;&gt;Ending thougths&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It would be better to gradually evolve your Neovim config over time instead of doing these large rewrites.
But afterwards it feels pretty good as I can once more try to claim with a straight face that I know what’s in my configuration and what it’s doing.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt; migration was more painful than I had expected.
It’s still an experimental nightly feature and it’s missing a lot of nice features that &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; has.
I’ll keep using &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt; as I think I’ve gotten it to a state of good enough but I’m looking forward to &lt;a href=&quot;https://neovim.io/doc/user/pack.html#vim.pack&quot;&gt;vim.pack&lt;/a&gt; becoming more feature complete.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fennel-lang.org/&quot;&gt;Fennel&lt;/a&gt; is fun to write in and I will keep using it where I can.
To be honest though, for basic configuration I was expecting &lt;a href=&quot;https://fennel-lang.org/&quot;&gt;Fennel&lt;/a&gt; to make a bigger difference than it did.
It’s nicer for sure but it’s nothing revolutionary.&lt;/p&gt;
&lt;p&gt;Then again, it’s the little things in life that matters.&lt;/p&gt;
&lt;div class=&quot;center&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/nvim-conf&quot;&gt;Link to my new Neovim config on Codeberg&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
</content></entry><entry><title>Automating the Hue Tap Dial Switch in Elixir via MQTT</title><id>http://jonashietala.se/blog/2025/09/01/automating_the_hue_tap_dial_switch_in_elixir_via_mqtt/index.html</id><updated>2025-09-01T12:14:57+00:00</updated><link href="https://www.jonashietala.se/blog/2025/09/01/automating_the_hue_tap_dial_switch_in_elixir_via_mqtt" rel="alternate"/><published>2025-09-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hue_tap_dial.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I recently bought a couple of &lt;a href=&quot;https://www.philips-hue.com/sv-se/p/hue-tap-dial-switch/8719514440999&quot;&gt;Hue Tap Dial&lt;/a&gt; switches for our house to enhance our smart home.
We have quite a few smart lights and I figured &lt;a href=&quot;https://www.philips-hue.com/sv-se/p/hue-tap-dial-switch/8719514440999&quot;&gt;the tap dial&lt;/a&gt;—with it’s multiple buttons and rotary dial—would be a good fit.&lt;/p&gt;
&lt;p&gt;Since I’ve been moving away from standard Home Assistant automations to &lt;a href=&quot;/blog/2024/10/08/writing_home_assistant_automations_using_genservers_in_elixir/&quot;&gt;my own automation engine in Elixir&lt;/a&gt; I had to figure out how best to integrate the tap dial.&lt;/p&gt;
&lt;p&gt;At first I tried to rely on my existing &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; connection but I realized that it’s better to bypass &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; and go directly via &lt;a href=&quot;https://mqtt.org/&quot;&gt;MQTT&lt;/a&gt;, as I already use &lt;a href=&quot;https://www.zigbee2mqtt.io/&quot;&gt;Zigbee2MQTT&lt;/a&gt; as the way to get Zigbee devices into &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This post walks through how I set it all up and I’ll end up with an example of how I control multiple Zigbee lights from one dial via Elixir.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;In the &lt;a href=&quot;/blog/2024/10/08/writing_home_assistant_automations_using_genservers_in_elixir/&quot;&gt;post about my automation engine&lt;/a&gt; I demonstrated how I controlled lights from Elixir via &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; states and actions.
For the devices that supports it, it’s better to communicate directly over &lt;a href=&quot;https://mqtt.org/&quot;&gt;MQTT&lt;/a&gt; as you’ll get better latency and more features.
Since then I’ve converted over most of my automations to be &lt;a href=&quot;https://mqtt.org/&quot;&gt;MQTT&lt;/a&gt; based.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;The-direct-zigbee-binding-is-good-but-not-great&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-direct-zigbee-binding-is-good-but-not-great&quot; class=&quot;heading-ref&quot;&gt;The direct zigbee binding is good but not great&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m a huge fan of using direct bindings in Zigbee to directly pair switches to lights.
This way the interaction is much snappier; instead of going through:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;device 1 -&gt; zigbee2mqtt -&gt; controller -&gt; zigbee2mqtt -&gt; device 2
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The communication can instead go:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;device 1 -&gt; device 2
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It works if my server is down, which is a huge plus for important functionality such as turning on the light in the middle of the night when one of the kids have soiled the bed.
That’s &lt;em&gt;not&lt;/em&gt; the time you want to debug your homelab setup!&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.philips-hue.com/sv-se/p/hue-tap-dial-switch/8719514440999&quot;&gt;Hue Tap Dial&lt;/a&gt; can be bound to lights with &lt;a href=&quot;https://www.zigbee2mqtt.io/&quot;&gt;Zigbee2MQTT&lt;/a&gt; and dimming the lights with the dial feels very smooth and nice.
You can also rotate the dial to turn on and off the light, like a normal dimmer switch.&lt;/p&gt;
&lt;p&gt;Unfortunately, if you want to bind the dimmer it also binds the hold of &lt;em&gt;all&lt;/em&gt; of the four buttons to turn off the light, practically blocking the hold functionality if you use direct binding.
There’s also no way to directly bind a button press to turn on or toggle the light—dimming and hold to turn off is what you get.&lt;/p&gt;
&lt;p&gt;To add more functionality you have to use something external; a Hue Bridge or &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; with a Zigbee dongle works, but I wanted to use Elixir.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Communicating-with-MQTT-in-Elixir&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Communicating-with-MQTT-in-Elixir&quot; class=&quot;heading-ref&quot;&gt;Communicating with MQTT in Elixir&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first thing we need to do is figure out is how to receive MQTT messages and how to send updates to Zigbee devices.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I use &lt;a href=&quot;https://www.zigbee2mqtt.io/&quot;&gt;Zigbee2MQTT&lt;/a&gt; as the Zigbee to MQTT bridge and &lt;a href=&quot;https://github.com/eclipse-mosquitto/mosquitto&quot;&gt;mosquitto&lt;/a&gt; as my MQTT server.
Messages may look different if you’re using another setup.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Connecting-and-subscribing-to-changes&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Connecting-and-subscribing-to-changes&quot; class=&quot;heading-ref&quot;&gt;Connecting and subscribing to changes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I found the &lt;a href=&quot;https://hexdocs.pm/tortoise311/0.12.1/introduction.html&quot;&gt;tortoise311&lt;/a&gt; library that implements an MQTT client and it was quite pleasant to use.&lt;/p&gt;
&lt;p&gt;First we’ll start a &lt;code&gt;Tortoise311.Connection&lt;/code&gt; in our main Supervisor tree:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Tortoise311&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;   &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Remember to generate a unique id if you want to connect multiple clients
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;   &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; to the same MQTT service.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;constant other keywords elixir&quot;&gt;client_id&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;my_unique_client_id&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;   &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; They don&amp;#39;t have to be on the same server.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;constant other keywords elixir&quot;&gt;server&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Tortoise311&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Tcp&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;host&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;localhost&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;port&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1883&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;   &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Messages will be sent to `Haex.MqttHandler`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;constant other keywords elixir&quot;&gt;handler&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;MqttHandler&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;   &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Subscribe to all events under `zigbee2mqtt`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;constant other keywords elixir&quot;&gt;subscriptions&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;zigbee2mqtt/+&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;The &lt;code&gt;zigbee2mqtt&lt;/code&gt; base topic is configurable in Zigbee2MQTT and you may need to tweak it for your setup.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;I’ll also add &lt;a href=&quot;https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html&quot;&gt;Phoenix PubSub&lt;/a&gt; to the Supervisor, which we’ll use to propagate MQTT messages to our automation:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When starting &lt;code&gt;Tortoise311.Connection&lt;/code&gt; above we configured it to call the &lt;code&gt;Haex.MqttHandler&lt;/code&gt; whenever an MQTT message we’re subscribing to is received.
Here we’ll simply forward any message to our PubSub, making it easy for anyone to subscribe to any message, wherever they are:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;MqttHandler&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Tortoise311&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Handler&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_message&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    payload &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Jason&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;decode!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;broadcast!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;join&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;/&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then in our automation (which in &lt;a href=&quot;/blog/2024/10/08/writing_home_assistant_automations_using_genservers_in_elixir/&quot;&gt;my automation system&lt;/a&gt; is a regular GenServer) we can subscribe to the events the Tap Dial creates:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Automation&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;TapDialExample&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; `My tap dial` is the name of the tap dial in zigbee2mqtt.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;subscribe&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;zigbee2mqtt/My tap dial&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    dbg&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If everything is setup correctly we should see messages like these when we operate the Tap Dial:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shortened output&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;payload #=&gt; %{
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &quot;action&quot; =&gt; &quot;button_1_press_release&quot;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;payload #=&gt; %{
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &quot;action&quot; =&gt; &quot;dial_rotate_right_step&quot;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &quot;action_direction&quot; =&gt; &quot;right&quot;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &quot;action_time&quot; =&gt; 15,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &quot;action_type&quot; =&gt; &quot;step&quot;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Controlling-devices&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Controlling-devices&quot; class=&quot;heading-ref&quot;&gt;Controlling devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To change the state of a device we should send a json payload to the “set” topic.
For example, to turn off a light named &lt;code&gt;My hue light&lt;/code&gt; we should send the payload 
&lt;code class=&quot;highlight json&quot;&gt;&lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;state&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;OFF&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; to &lt;code&gt;zigbee2mqtt/My hue light/set&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s a function to send payloads to our light:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;Tortoise311&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;publish&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Important that this id matches the `client_id`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; we gave to Tortoise311.Connection.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;my_unique_client_id&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;zigbee2mqtt/My hue light/set&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Jason&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;encode!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;The payloads and capabilities are different for each device; &lt;a href=&quot;https://www.zigbee2mqtt.io/devices/9290024688.html&quot;&gt;here’s the information&lt;/a&gt; for the Hue light I’m using in this example.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Button-presses&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Button-presses&quot; class=&quot;heading-ref&quot;&gt;Button presses&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the MQTT communication done, we can start writing some automations.&lt;/p&gt;
&lt;section id=&quot;Normal-press&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Normal-press&quot; class=&quot;heading-ref&quot;&gt;Normal press&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here’s how we can toggle the light on/off when we click the first button on the dial in our GenServer:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;button_1_press_release&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;TOGGLE&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Remember that we subscribed to the 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;zigbee2mqtt/My tap dial&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; topic during &lt;code&gt;init&lt;/code&gt;.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Hold&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Hold&quot; class=&quot;heading-ref&quot;&gt;Hold&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can also hold a button, which generates a &lt;code&gt;hold&lt;/code&gt; and a &lt;code&gt;hold_release&lt;/code&gt; event.
Here’s how to use them to start moving through the hues of a light when you hold down a button and stop when you release it.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;button_3_hold&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue_move&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;saturation&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;button_3_hold_release&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue_move&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Double-clicking&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Double-clicking&quot; class=&quot;heading-ref&quot;&gt;Double clicking&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;How about double clicking?&lt;br&gt;
You could track the timestamp of the presses in the GenServer state and check the duration between them to determine if it’s a double click or not; maybe something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;button_2_press_release&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  double_click_limit &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;350&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  now &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;utc_now&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator logical elixir&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;diff&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;now&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;millisecond&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;&amp;lt;&lt;/span&gt; double_click_limit &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; If we double clicked.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;color&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; If we single clicked.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;color&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;180&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; now&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This however executes an action on the first and second click.
To get around that we could add a timeout for the first press by sending ourselves a delayed message, with the downside of introducing a small delay for single clicks:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;button_2_press_release&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  double_click_limit &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;350&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  now &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;utc_now&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator logical elixir&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;diff&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;now&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;millisecond&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;&amp;lt;&lt;/span&gt; double_click_limit &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;color&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;180&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; The double click clause is the same as before except we also remove `click_ref`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; to signify that we&amp;#39;ve handled the interaction as a double click.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      state
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; When we first press a key we shouldn&amp;#39;t execute it directly,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; instead we send ourself a message to handle it later.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Use `make_ref` signify which press we should handle.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    ref &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; make_ref&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send_after&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;execute_single_press&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; ref&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; double_click_limit&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      state
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; now&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; ref&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;&lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This is the delayed handling of a single button press.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;execute_single_press&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; ref&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; If the stored reference doesn&amp;#39;t exist we&amp;#39;ve handled it as a double click.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; If we press the button many times (completely mash the button) then
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; we might enter a new interaction and `click_ref` has been replaced by a new one.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This equality check prevents such a case, allowing us to only act on the very
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; last press.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This is also useful if we in the future want to add double clicks to other buttons.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; ref &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;color&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can generalize this concept to triple presses and beyond by keeping a list of timestamps instead of the singular one we use in 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;/code&gt;,
but I personally haven’t found a good use-case for them.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;You might be able to utilize &lt;a href=&quot;https://hexdocs.pm/elixir/Process.html#cancel_timer/2&quot;&gt;Process.cancel_timer/2&lt;/a&gt; as an alternative to the &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#make_ref/0&quot;&gt;make_ref/0&lt;/a&gt; approach I’m using.
In theory I guess it’s the better approach as you don’t need to process obsolete messages but &lt;del&gt;I’m too lazy to rewrite it&lt;/del&gt; I leave that as an exercise to the reader.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Dimming&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Dimming&quot; class=&quot;heading-ref&quot;&gt;Dimming&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, let’s see if we can create a smooth dimming functionality.
This is &lt;a href=&quot;https://community.home-assistant.io/t/philips-tap-dial-switch-with-double-tap-and-4-dial-actions/618988/106&quot;&gt;surprisingly problematic&lt;/a&gt;
but let’s see what we can come up with.&lt;/p&gt;
&lt;p&gt;Rotating the dial produces a few different actions:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;dial_rotate_left_step
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dial_rotate_left_slow
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dial_rotate_left_fast
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dial_rotate_right_step
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dial_rotate_right_slow
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dial_rotate_right_fast
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;brightness_step_up
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;brightness_step_down
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s start with &lt;code&gt;dial_rotate_*&lt;/code&gt; to set the &lt;code&gt;brightness_step&lt;/code&gt; attribute of the light:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;dial_rotate_&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator binary-concatenation elixir&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; type&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  speed &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; rotate_speed&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_step&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; speed&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;rotate_speed&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;left_&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator binary-concatenation elixir&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; speed&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;do:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;-&lt;/span&gt;rotate_speed&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;speed&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;rotate_speed&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;right_&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator binary-concatenation elixir&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; speed&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;do:&lt;/span&gt;&lt;/span&gt; rotate_speed&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;speed&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;rotate_speed&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;step&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;do:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;rotate_speed&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;slow&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;do:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;20&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;rotate_speed&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;fast&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;do:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;45&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works, but the transitions between the steps aren’t smooth as the light immediately jumps to a new brightness value.&lt;/p&gt;
&lt;p&gt;With a transition we can smooth it out:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;&lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; I read somewhere that 0.4 is standard for Philips Hue.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_step&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; speed&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s actually fairly decent (when the stars align).&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;There’s also an &lt;code&gt;action_time&lt;/code&gt; attribute that’s sent together with &lt;code&gt;dial_rotate_*&lt;/code&gt;, signifying how long the action took.
I tried to incorporate it into the dimmer calculation but I didn’t manage to integrate it in a way that felt like an improvement
over the simpler approach outlined above.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;As an alternative implementation we can try to use the &lt;code&gt;brightness_step_*&lt;/code&gt; actions:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;brightness_step_&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator binary-concatenation elixir&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; dir&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action_step_size&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; step
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      state
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  step &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; dir &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;up&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; step
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;down&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;-&lt;/span&gt;step
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Dimming was a little slow, adding a factor speeds things up.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_step&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; step &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This implementation lets the tap dial itself provide the amount of steps and I do think it feels better than the &lt;code&gt;dial_rotate_*&lt;/code&gt; implementation.&lt;/p&gt;
&lt;p&gt;Note that this won’t completely turn off the light and it’ll stop at brightness &lt;code&gt;1&lt;/code&gt;.
We can instead provide 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_step_onoff&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; step&lt;/code&gt; to allow the dimmer to turn on and off the light too.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;When I first implemented this the dimming was really choppy and felt awful,
which led me to create a more elaborate implementation that ultimately spawned this blog post.&lt;/p&gt;
&lt;p&gt;As I’m rewriting this post I’ve noticed the choppiness in my more elaborate implementation too (leading me to delete it entirely).&lt;/p&gt;
&lt;p&gt;I think it’s due to the unreliable latency in the Zigbee network that occasionally cause delays that mess up the responsiveness, regardless of the implementation.
Sometimes you’ll get a long delay before you receive a message or you might get a bunch of messages at the same time.&lt;/p&gt;
&lt;p&gt;I guess the only way to &lt;em&gt;really&lt;/em&gt; fix this is to bind the dial to the light directly.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Other-types-of-transitions&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Other-types-of-transitions&quot; class=&quot;heading-ref&quot;&gt;Other types of transitions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the reasons I wanted a custom implementation was to be able to do other things with the rotary dial.&lt;/p&gt;
&lt;p&gt;For example, maybe I’d like to alter the hue of light by rotating?
All we have to do is set the hue instead of the brightness:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue_step&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; step &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0.75&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(This produces a very cool effect!)&lt;/p&gt;
&lt;p&gt;Another idea is to change the volume by rotating.
Here’s the code that I use to control the volume of our kitchen speakers (via Home Assistant, not MQTT):&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;rotate&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; step &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; A step of 8 translates to a volume increase of 3%
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  volume_step &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; step &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Clamp volume to not accidentally set a very loud or silent volume.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  volume &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; HAStates stores the current states in memory whenever a state is changed.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;HAStates&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;get_attribute&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;kitchen_player_ha&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;volume_level&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;+&lt;/span&gt; volume_step&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;clamp&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Calls the `media_player.volume_set` action.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;MediaPlayer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set_volume&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;kitchen_player_ha&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; volume&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Prevents a possible race condition where we use the old volume level
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; stored in memory for the next rotation.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;HAStates&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;override_attribute&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;kitchen_player_ha&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;volume_level&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; volume&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;A-use-case-the-boys-bedroom&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#A-use-case-the-boys-bedroom&quot; class=&quot;heading-ref&quot;&gt;A use-case: the boys bedroom&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ve got a bunch of lights in the boys bedroom that we can control and it’s a good use-case for a device such as the Tap Dial.&lt;/p&gt;
&lt;section id=&quot;Lights-to-control&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Lights-to-control&quot; class=&quot;heading-ref&quot;&gt;Lights to control&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are the lights we can control in the room:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
A ceiling light with color ambiance
&lt;/li&gt;
&lt;li&gt;
A window light with white ambiance
&lt;/li&gt;
&lt;li&gt;
A floor lamp with white ambiance
&lt;/li&gt;
&lt;li&gt;
Night lights for both Loke and Isidor, with color ambiance
&lt;/li&gt;
&lt;li&gt;
A lava lamp for Loke, connected to a smart plug
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(Yes, I need to get a lava light for Isidor too. They’re awesome!)&lt;/p&gt;
&lt;p&gt;The window light isn’t controlled by the tap dial and there are other automations that controls circadian lighting for most of the lights.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Use-Zigbee-direct-binding&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Use-Zigbee-direct-binding&quot; class=&quot;heading-ref&quot;&gt;Use Zigbee direct binding&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’m opting to use direct binding because of two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Direct binding allows us to dim the light even if the smart home server is down.
&lt;/li&gt;
&lt;li&gt;
Despite my efforts, the dimming automation has some latency issues.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Even though it overrides the hold functionality I think direct binding for lights is the way to go.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-functionality&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#The-functionality&quot; class=&quot;heading-ref&quot;&gt;The functionality&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are the functions for the tap dial in the boys room:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rotate&lt;/strong&gt;: Dim brightness of ceiling light (direct binding)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold any&lt;/strong&gt;: Turns off the ceiling light (direct binding)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click 1&lt;/strong&gt;: Toggle ceiling light on/off
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double click 1&lt;/strong&gt;: Toggle max brightness for ceiling light on/off
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click 2&lt;/strong&gt;: Each click goes through different colors for the ceiling light
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click 3&lt;/strong&gt;: Toggle floor lamp on/off
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double click 3&lt;/strong&gt;: Toggle Isidor’s night light on/off
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold 3&lt;/strong&gt;: Loop through the hue of Isidor’s night light
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click 4&lt;/strong&gt;: Toggle Loke’s lava lamp on/off
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double click 4&lt;/strong&gt;: Toggle Loke’s night light on/off
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold 4&lt;/strong&gt;: Loop through the hue of Loke’s night light
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There’s many different ways you can design the interactions and I may switch it up in the future, but for now this works well.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;While I normally wouldn’t use direct bindings together with hold functionality (as here it will also turn off the ceiling light), in this case I think it works well.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;A-generalized-tap-dial-controller&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#A-generalized-tap-dial-controller&quot; class=&quot;heading-ref&quot;&gt;A generalized tap dial controller&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The code I’ve shown you so far has been a little simplified to explain the general approach.
As I have several tap dials around the house I’ve made a general tap dial controller with a more declarative approach.&lt;/p&gt;
&lt;p&gt;For example, here’s how the tap dial in the boys room is defined:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;TapDialController&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;device&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; boys_room_tap_dial&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;scene&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;rotate&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; _step &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This disables the existing circadian automation.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; I found that manually disabling it is more reliable than trying to
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; detect external changes over MQTT as messages may be delayed and arrive out of order.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;LightController&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set_manual_override&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;boys_room_ceiling_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;button_1&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;click&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;boys_room_ceiling_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;TOGGLE&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;double_click&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This function compares the current light status and sets it to 100%
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; or reverts back to circadian lighting (if setup for the light).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;HueLights&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;toggle_max_brightness&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;boys_room_ceiling_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;button_2&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;click&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; state &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; The light controller normally uses circadian lighting to update
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; the light. Setting manual override pauses circadian lighting,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; allowing us to manually control the light.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;LightController&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set_manual_override&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;boys_room_ceiling_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This function steps through different light states for the ceiling light
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; (hue 0..300 with 60 intervals) and stores it in `state`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      next_scene&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;button_3&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;click&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;boys_room_floor_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;TOGGLE&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;double_click&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;isidor_sleep_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;TOGGLE&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;hold&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;isidor_sleep_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue_move&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;saturation&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;hold_release&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;isidor_sleep_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue_move&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;button_4&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;click&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;loke_lava_lamp&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;TOGGLE&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;254&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;double_click&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;loke_sleep_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;TOGGLE&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;hold&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;loke_sleep_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue_move&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;saturation&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;hold_release&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;set&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;loke_sleep_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;hue_move&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m not going to go through the implementation of the controller in detail.
Here’s the code you can read through if you want:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;TapDialController&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Mock&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This allows us to setup expectations and to collect what messages
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; the controller sends during unit testing.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; parent &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;parent&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;allow&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;parent&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    device &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;device&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator other elixir&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Must specify `device`, got: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;inspect&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Just subscribes to pubsub under the hood.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;subscribe_events&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;device&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;new&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put_new&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;double_click_timeout&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;350&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;start_link&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mqtt&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _topic&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; parse_action&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; button&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; fun&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;        &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; We specify handlers with `button_3: %{}` specs.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; fetch_button_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;button&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; spec&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;            &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Dispatch to action handlers, such as `handle_hold` and `handle_press_release`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            fun&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;not_found&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;rotate&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; step&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; fetch_rotate_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; cb&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            call_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;cb&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; step&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;not_found&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;skip&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;execute_single_press&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; ref&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; cb&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Only execute the callback for the last action.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; ref &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      call_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;cb&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_press_release&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    single_click_handler &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; spec&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    double_click_handler &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; spec&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;double_click&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;cond&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      double_click_handler &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        now &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;utc_now&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        valid_double_click? &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator logical elixir&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;diff&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;now&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;millisecond&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;&amp;lt;&lt;/span&gt; state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;double_click_timeout
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; valid_double_click? &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;          &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Execute a double click immediately.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;          state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            state
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          call_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;double_click_handler&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;          &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Delay single click to see if we get a double click later.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;          ref &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; make_ref&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send_after&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;execute_single_press&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; ref&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; single_click_handler&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;double_click_timeout
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            state
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;last_press&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; now&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;click_ref&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; ref&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      single_click_handler &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;        &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; No double click handler, so we can directly execute the single click.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        call_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;single_click_handler&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_hold&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    call_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;hold&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_hold_release&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    call_handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;hold_release&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;call_handler&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant language elixir&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;call_handler&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; If a callback expects one argument we&amp;#39;ll also send the state,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; otherwise we simply call it.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;info&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;arity&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        handler&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; handler&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      x &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Unsupported cb arity `&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;` for &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;device&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt; tap dial expecting 0 or 1 args&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;call_handler&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant language elixir&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; _arg1&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;call_handler&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; arg1&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;info&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;arity&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        handler&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;arg1&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant numeric elixir&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; handler&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;arg1&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      x &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Unsupported cb arity `&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;` for &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;device&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt; tap dial  expecting 1 or 2 args&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;parse_action&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;brightness_step_&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator binary-concatenation elixir&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; dir&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action_step_size&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; step&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    step &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; dir &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;up&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; step
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;down&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;-&lt;/span&gt;step
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;rotate&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; step&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;parse_action&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;action&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; action&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Regex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~r&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string interpolated elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;meta group regexp elixir&quot;&gt;&lt;span class=&quot;keyword control group regexp elixir&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp elixir&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp elixir&quot;&gt;&lt;span class=&quot;constant other escape-sequence regexp elixir&quot;&gt;\d&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp elixir&quot;&gt;&lt;span class=&quot;keyword control group regexp elixir&quot;&gt;&lt;span class=&quot;punctuation definition group end regexp elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta literal regexp elixir&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;meta group regexp elixir&quot;&gt;&lt;span class=&quot;keyword control group regexp elixir&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp elixir&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp elixir&quot;&gt;&lt;span class=&quot;constant other escape-sequence regexp elixir&quot;&gt;\w&lt;/span&gt;&lt;span class=&quot;meta quantifier regexp elixir&quot;&gt;&lt;span class=&quot;keyword operator quantifier regexp elixir&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp elixir&quot;&gt;&lt;span class=&quot;keyword control group regexp elixir&quot;&gt;&lt;span class=&quot;punctuation definition group end regexp elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; action&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;capture&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;all_but_first&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;button&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;press_release&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;to_integer&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;button&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable other capture elixir&quot;&gt;&lt;span class=&quot;keyword operator capture elixir&quot;&gt;&amp;amp;&lt;/span&gt;handle_press_release&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;button&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;hold&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;to_integer&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;button&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable other capture elixir&quot;&gt;&lt;span class=&quot;keyword operator capture elixir&quot;&gt;&amp;amp;&lt;/span&gt;handle_hold&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;button&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;hold_release&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;to_integer&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;button&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable other capture elixir&quot;&gt;&lt;span class=&quot;keyword operator capture elixir&quot;&gt;&amp;amp;&lt;/span&gt;handle_hold_release&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      _ &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;skip&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;parse_action&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_action&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;debug&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Skip fallback tap dial action: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;inspect&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;action&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;skip&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;fetch_button_handler&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;button&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    spec &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;button_&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;to_atom&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; spec &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;spec&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; button&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;not_found&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;fetch_rotate_handler&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; spec &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;rotate&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; spec&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;not_found&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
</content></entry><entry><title>I&apos;ll only buy devices with GrapheneOS</title><id>http://jonashietala.se/blog/2025/08/28/ill_only_buy_devices_with_grapheneos/index.html</id><updated>2025-09-05T05:53:47+00:00</updated><link href="https://www.jonashietala.se/blog/2025/08/28/ill_only_buy_devices_with_grapheneos" rel="alternate"/><published>2025-08-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;Cops say criminals use a Google Pixel with GrapheneOS — I say that’s freedom
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://www.androidauthority.com/why-i-use-grapheneos-on-pixel-3575477/&quot;&gt;Calvin Wankhede&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;We’re in a dark time period right now.&lt;/p&gt;
&lt;p&gt;Authoritarianism is on the rise throughout the globe.
Governments wants to monitor your social media accounts so they can make you disappear if you engage in wrongthink such as opposing wars or genocide.
This is worsened by misguided laws like &lt;a href=&quot;https://fightchatcontrol.eu/&quot;&gt;Chat control&lt;/a&gt; that would mandate scanning of all digital communication,
exposing any wrongthink in your “private messages”.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Silly me, &lt;a href=&quot;https://fightchatcontrol.eu/&quot;&gt;Chat control&lt;/a&gt; doesn’t mandate scanning of &lt;em&gt;all&lt;/em&gt; digital communication; politicians and their families are, predictably, exempt.
Rules for thee but not for me.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;A rational reaction to threats is to “shell up” and try to make your personal space safe.
This is increasingly difficult as the devices you buy often doesn’t feel like &lt;em&gt;yours&lt;/em&gt; anymore.
Files are moved to the cloud without your knowledge;
companies are doing everything they can to prevent you from blocking the ads they’re shoving in everywhere;
and everything you do will soon be ingested by an LLM in order to present personalized slop to you
(even your passwords and screenshots of any nasty porn habits you may have).&lt;/p&gt;
&lt;p&gt;While you can avoid most of this crap on computers (try Linux if you haven’t) the situation on smartphones is much bleaker.
Apple has been blocking sideloading apps for years and Google will soon follow by &lt;a href=&quot;https://news.ycombinator.com/item?id=45017028&quot;&gt;only allowing apps from verified developers to be installed on Android&lt;/a&gt;,
preventing you from installing what &lt;em&gt;you&lt;/em&gt; want.&lt;/p&gt;
&lt;p&gt;(They claim it’s “for security” but it’s obvious they’re doing this to protect their income stream. Apple takes a ridiculous 30% cut from all sales in their walled garden
and Google hates the ability to strip out their ads.)&lt;/p&gt;
&lt;p&gt;I like the idea of a “dumb phone” but I unfortunately need and want apps on my phone
(I consider banking and authentication apps essential to surviving in the modern world, and sometimes you &lt;em&gt;must&lt;/em&gt; run an Android or iOS app).
A “degoogled” Android-compatible operating system is the answer I see, with &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; as the exceptional standout.&lt;/p&gt;
&lt;p&gt;The big dragons recognize this as for example Samsung &lt;a href=&quot;https://sammyguru.com/breaking-samsung-removes-bootloader-unlocking-with-one-ui-8/&quot;&gt;removes bootloader unlocking&lt;/a&gt; and the &lt;a href=&quot;https://www.reddit.com/r/degoogle/comments/1mau7yl/eu_age_verification_app_to_ban_any_android_system/?share_id=iR05aexja3cz3w-ITsqz1&quot;&gt;EU age verification app may ban Android systems not licensed by Google&lt;/a&gt;.
In true Streisand fashion this only makes me more motivated to fight back.&lt;/p&gt;
&lt;section id=&quot;GrapheneOS-works-and-its-convenient&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#GrapheneOS-works-and-its-convenient&quot; class=&quot;heading-ref&quot;&gt;GrapheneOS works and it’s convenient&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/grapheneos/tablet.jpg&quot;&gt;
&lt;figcaption&gt;Installing &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; on the Pixel Tablet.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;When people talk about &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; they will understandably focus on the privacy and security aspect.
I’ll go into it a &lt;a href=&quot;#The-best-privacy-security-in-a-modern-phone&quot;&gt;later&lt;/a&gt;
but I think it’s important to first dispel the idea that &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; is only for the hardcore tech savvy user or that you’ll have to sacrifice a lot of functionality.&lt;/p&gt;
&lt;p&gt;While &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; isn’t quite as simple as stock Android (I had to tweak a few settings to get some apps working)
the experience has been very smooth.&lt;/p&gt;
&lt;section id=&quot;Installation&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Installation&quot; class=&quot;heading-ref&quot;&gt;Installation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The installation was straightforward and worked without a hitch:&lt;/p&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
Plug in the phone or tablet via an USB
&lt;/li&gt;
&lt;li&gt;
Launch Chrome (or chromium)
&lt;/li&gt;
&lt;li&gt;
Follow the instructions and click some buttons
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;App-compatibility&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#App-compatibility&quot; class=&quot;heading-ref&quot;&gt;App compatibility&lt;/a&gt;&lt;/h3&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/grapheneos/Kvaesitso.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/grapheneos/Kvaesitso.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/grapheneos/more_apps.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/grapheneos/more_apps.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Some of the apps I’ve got installed.
I use the &lt;a href=&quot;https://github.com/MM2-0/Kvaesitso&quot;&gt;Kvaesitso&lt;/a&gt; launcher.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Apps are also just as easy to install as on stock Android.
I’ve installed most of the apps from the Play Store just as I would’ve on stock and they work just fine.&lt;/p&gt;
&lt;p&gt;So far I’ve had a grand total of two issues with any apps I’ve tried:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;At first I couldn’t copy BankID over from my old phone.&lt;/p&gt;
&lt;p&gt;I had to tweak some permissions and disable some of the location privacy features of &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; before the phones recognized each other.
Presumably there’s some security measure there so that you can only copy it if the phones are nearby.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/grapheneos/location.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/grapheneos/location.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/grapheneos/location_services.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/grapheneos/location_services.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;I had to play with some of these location settings to be able to copy BankID from my old phone to the new one.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The AI detection feature of &lt;a href=&quot;https://macrofactorapp.com/&quot;&gt;MacroFactor&lt;/a&gt; refused to work.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://macrofactorapp.com/&quot;&gt;MacroFactor&lt;/a&gt; is a food tracking app where you can take a photo and it’ll try to infer the food from the picture but uploading the photo simply failed.
It’s a pretty cool feature and I instead use the app &lt;a href=&quot;https://cronometer.com/index.html&quot;&gt;Cronometer&lt;/a&gt; that has the same functionality.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://macrofactorapp.com/&quot;&gt;MacroFactor&lt;/a&gt; uses Play Integrity which may in some cases break certain apps.
I’ve got a few other apps that also uses Play Integrity but they don’t have any issues.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I was worried that I’d run into issues with the banking apps as I know there are some banking apps that have issues, but all the Swedish banking apps I’ve tried work well.&lt;/p&gt;
&lt;p&gt;You can of course install apps from other sources such as &lt;a href=&quot;https://f-droid.org/&quot;&gt;F-Droid&lt;/a&gt;, &lt;a href=&quot;https://accrescent.app/&quot;&gt;Accrescent&lt;/a&gt;, &lt;a href=&quot;https://obtainium.imranr.dev/&quot;&gt;Obtanium&lt;/a&gt;, or manually as well.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I had a lot more compatibility issues on &lt;a href=&quot;https://calyxos.org/&quot;&gt;CalyxOS&lt;/a&gt; on my old phone than I’ve had with &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt;.
The sandboxed Google Play is an obviously superior solution than the MicroG/Aurora setup on &lt;a href=&quot;https://calyxos.org/&quot;&gt;CalyxOS&lt;/a&gt;, and not just for privacy reasons.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;No-bloatware&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#No-bloatware&quot; class=&quot;heading-ref&quot;&gt;No bloatware&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Finally, I love that there’s no bloatware bullshit on &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt;.
There are no shitty vendor specific apps that you cannot uninstall and it isn’t trying to trick you into installing stupid games via dark patterns.
The downside is that &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; doesn’t come with a lot of customization and lets you install apps for that yourself.&lt;/p&gt;
&lt;p&gt;In short, it feels like with &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; you’re in control, not some mega corporation.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;The-best-privacy-security-in-a-modern-phone&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-best-privacy-security-in-a-modern-phone&quot; class=&quot;heading-ref&quot;&gt;The best privacy &amp;amp; security in a modern phone&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While other Android compatible distributions such as &lt;a href=&quot;https://calyxos.org/&quot;&gt;CalyxOS&lt;/a&gt; and &lt;a href=&quot;https://www.lineageos.org/&quot;&gt;LineageOS&lt;/a&gt; all mention privacy and security as benefits they’re nothing like &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt;.
In some cases—as with &lt;a href=&quot;https://calyxos.org/&quot;&gt;CalyxOS&lt;/a&gt; where security updates have seen &lt;em&gt;significant&lt;/em&gt; delays—they may provide even less security compared to stock Android.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://calyxos.org/&quot;&gt;CalyxOS&lt;/a&gt; &lt;a href=&quot;https://calyxos.org/news/2025/08/01/a-letter-to-our-community/&quot;&gt;recently announced&lt;/a&gt; that updates will be paused for 4–6 months and they recommend you to uninstall the OS.
See &lt;a href=&quot;https://discuss.grapheneos.org/d/24791-departure-of-calyx-calyxos-leadership-and-discontinuation-of-calyxos-updates&quot;&gt;more discussion on the GrapheneOS forum&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Everything I’ve read suggests that &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; takes security and privacy very seriously.
I feel that sometimes they may take a too extreme stance but I can respect that, despite being overkill for the threat levels I care about.&lt;/p&gt;
&lt;p&gt;See for example &lt;a href=&quot;https://eylenburg.github.io/android_comparison.htm&quot;&gt;this comparison of Android-based Operating Systems&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What about Apple then?
Aren’t they great at privacy and security?
While I’m sure they’ll respect your privacy more than Google,
I just can’t trust a company that &lt;a href=&quot;https://daringfireball.net/2025/06/more_on_apples_trust-eroding_f1_the_movie_wallet_ad&quot;&gt;shoves ads into their wallet app&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Pixel-devices-the-big-drawback-with-GrapheneOS&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Pixel-devices-the-big-drawback-with-GrapheneOS&quot; class=&quot;heading-ref&quot;&gt;Pixel devices, the big drawback with GrapheneOS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It would’ve been great to have more choices.
If I only looked at hardware I might have gotten the &lt;a href=&quot;https://shop.fairphone.com/fairphone-5&quot;&gt;Fairphone 5&lt;/a&gt; as I like the idea of repairability, ethically sourced components, and a phone made in the EU.
I also like the idea of a smaller phone and a Flip phone would’ve been great.
Or maybe a really cheap phone (or tablet) as I don’t care that much about performance and could save some money.&lt;/p&gt;
&lt;p&gt;But alas, &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; only support Pixel devices (&lt;a href=&quot;https://grapheneos.social/@GrapheneOS/115102564799343519&quot;&gt;for now&lt;/a&gt;).
There’s a handful of phones to choose from but only a single tablet.&lt;/p&gt;
&lt;p&gt;I guess the best way to degoogle right now is to buy from Google…
So I got the Pixel 9a for myself and the Pixel Tablet for our family.
(Admittedly, they’ve been pretty great.)&lt;/p&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update &lt;span class=&quot;date&quot;&gt;2025-09-02&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;GrapheneOS supports so few devices because there’s simply so few devices that are both highly secure and support alternate operating systems.
Some of these requirements are &lt;a href=&quot;https://grapheneos.org/faq#future-devices&quot;&gt;outlined in their FAQ&lt;/a&gt; and it’s an illuminating read.&lt;/p&gt;
&lt;p&gt;Fairphone for example &lt;a href=&quot;https://discuss.grapheneos.org/d/24134-devices-lacking-standard-privacysecurity-patches-and-protections-arent-private&quot;&gt;significantly lag behind on security updates&lt;/a&gt; (among other things).&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Software-is-more-important-than-hardware&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Software-is-more-important-than-hardware&quot; class=&quot;heading-ref&quot;&gt;Software is more important than hardware&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve had an interesting shift when I evaluate mobile devices;
instead of comparing phones primarily by hardware I prioritize the software on the phone.&lt;/p&gt;
&lt;p&gt;Today, more than ever, hardware upgrades in new phones provide diminishing returns
for ever increasing prices.
There’s little practical difference between a new phone and a phone from a few years ago
and savvy people can save a lot of money by simply avoiding the constant stream of new releases.&lt;/p&gt;
&lt;p&gt;Before I bought the Pixel 9a I used the &lt;a href=&quot;https://shop.fairphone.com/fairphone-4&quot;&gt;Fairphone 4&lt;/a&gt; for almost 4 years, and it was performing just fine!
If I hadn’t gotten the urge of trying out &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; I would’ve still be happy with the Fairphone hardware (which was a bit underpowered already at release).&lt;/p&gt;
&lt;p&gt;Software on the other hand is more important than ever and for me it’s what makes or breaks a phone today.&lt;/p&gt;
&lt;p&gt;The right software will protect your privacy and help keep your device secure,
while the wrong software will fill your phone with uninstallable bloatware and cripple performance after system updates (if they deign to provide them).&lt;/p&gt;
&lt;p&gt;For example, I’ve used a Galaxy Tab A7 Lite as a dashboard for my smart home for a while and it worked great.
Then I installed an update and it suddenly became extremely slow, so slow that you barely could interact with the UI without punching the damn device.
Even though the hardware is great, Samsung crippled the device for no reason.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Punching the device did not in fact help speed it up.
Shocking.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;With the right software your device works for you, not against you.
It’s not a lot to ask for, yet in the modern day that’s very rare indeed, and it’s why I’ll only be buying mobile devices supported by &lt;a href=&quot;https://grapheneos.org/&quot;&gt;GrapheneOS&lt;/a&gt; for the foreseeable future.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Ditching Sonos for Music Assistant</title><id>http://jonashietala.se/blog/2025/06/04/ditching_sonos_for_music_assistant/index.html</id><updated>2025-06-04T14:04:31+00:00</updated><link href="https://www.jonashietala.se/blog/2025/06/04/ditching_sonos_for_music_assistant" rel="alternate"/><published>2025-06-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;My general advice for life is: be a good person, and care for the people around you. And follow this one very specific rule: &lt;strong&gt;avoid vendor lock-in&lt;/strong&gt;.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Sean Boots &lt;a href=&quot;https://sboots.ca/2021/05/12/rule-number-one-avoid-vendor-lock-in/&quot;&gt;Rule number one: Avoid vendor lock-in&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;I’ve always wondered how to setup a sound systems around the house that you can control from your devices, such as your phone.
To get a working setup it seemed you had to embrace vendor lock-in;
either by committing to an entire ecosystem such as &lt;a href=&quot;https://www.sonos.com/&quot;&gt;Sonos&lt;/a&gt;,
or by relying on a service like Spotify and buying amplifiers that supports their particular integration (such as &lt;a href=&quot;https://connect.spotify.com/&quot;&gt;Spotify Connect&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;When I wanted to replace and upgrade our old Sonos speaker I did som research and I found a promising alternative: it’s called &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; and it’s great.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/ma_dashboard.png&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; dashboard.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;section id=&quot;The-woes-of-Sonos&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-woes-of-Sonos&quot; class=&quot;heading-ref&quot;&gt;The woes of Sonos&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ve had a Sonos speaker in our kitchen for more than a decade.
At first I was very happy with it; the speaker was easy to use, it integrated well with Spotify, and despite being a single fairly cheap speaker the sound was pretty good.&lt;/p&gt;
&lt;p&gt;But gradually the experience got worse:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
The speaker sometimes refused to play songs via Spotify.
&lt;/li&gt;
&lt;li&gt;
We couldn’t connect to the speaker via the Sonos app (having to unplug the speaker and pray to the Sonos god that it would be enough to fix it).
&lt;/li&gt;
&lt;li&gt;
Playback randomly paused.
&lt;/li&gt;
&lt;li&gt;
The speaker lost WIFI connection, reconnecting after a while.
&lt;/li&gt;
&lt;li&gt;
Finally, the radio integration stopped working altogether (this is critical for my girlfriend who always listens to the radio).
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It could be worse—at least our speaker wasn’t &lt;a href=&quot;https://news.ycombinator.com/item?id=21895086&quot;&gt;bricked&lt;/a&gt; and we (supposedly) dodged a bunch of other issues by never upgrading to the new app.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-new-setup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-new-setup&quot; class=&quot;heading-ref&quot;&gt;The new setup&lt;/a&gt;&lt;/h2&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; as the central controller for streaming music and radio to different players and speakers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup an &lt;a href=&quot;https://www.arylic.com/products/arylic-a50-wifi-bluetooth-multiroom-full-digital-hifi-amplifier-with-airplay-dlna-multiroom-control&quot;&gt;Arylic A50+&lt;/a&gt; amplifier that &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; can control.&lt;/p&gt;
&lt;p&gt;Together with a pair of speakers it replaces the Sonos in the kitchen.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; with &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; to control playback via our smart-home dashboard and automations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup more players for &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; to control.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;What-is-Music-Assistant-and-why-is-it-awesome&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#What-is-Music-Assistant-and-why-is-it-awesome&quot; class=&quot;heading-ref&quot;&gt;What is &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; and why is it awesome?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; is a service that acts as a hub that connects different providers and players, letting you control the sound in your home from one central location.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/ma_how_it_worps.jpg&quot;&gt;
&lt;figcaption&gt;Image showing how &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; bridges different sources with different players.
Taken from &lt;a href=&quot;https://www.home-assistant.io/blog/2024/05/09/music-assistant-2/&quot;&gt;this Home Assistant blog post&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;So you could have this kind of setup and let &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; connect them together in whatever way you wish, including multi-room setups (if the players are from the same ecosystem, such as Airplay or Squeezebox):&lt;/p&gt;
&lt;table class=&quot;center&quot;&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Provider&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Player&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Spotify&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Sonos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Audible&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Chromecast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Radio&lt;/td&gt;
&lt;td&gt;→&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Media player in Home Assistant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Plex&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Streaming amplifier (Squeezebox)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Local storage&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Computer with Linux (Squeezebox)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Careful to not get nerd sniped;
with room presence detection you could have the music follow you automatically as you move around the house.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Here’s a few reasons why I think &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; is awesome:&lt;/p&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Freedom from the limitations of one ecosystem.
&lt;/li&gt;
&lt;li&gt;
Can mix and match music from local storage and Spotify in the same playlist.
&lt;/li&gt;
&lt;li&gt;
One place to control all your speakers of varying types and connections.
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.home-assistant.io/blog/2024/05/09/music-assistant-2/&quot;&gt;Integrates well with Home Assistant&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt;, as it’s name hints at, started out as a &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; component.
That’s why I initially dismissed it but &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; is now a standalone service.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;How-to-set-it-up&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#How-to-set-it-up&quot; class=&quot;heading-ref&quot;&gt;How to set it up&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.music-assistant.io/installation/&quot;&gt;Install Music Assistant&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I host my homelab things using docker compose and it was as simple as:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;yaml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight yaml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;services&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;music-assistant-server&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;image&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;ghcr.io/music-assistant/server:latest&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;container_name&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;music-assistant-server&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;restart&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;unless-stopped&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line number-sign yaml&quot;&gt;&lt;span class=&quot;punctuation definition comment line number-sign yaml&quot;&gt;#&lt;/span&gt; Network mode must be set to host for MA to work correctly
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;network_mode&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;host&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;volumes&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation definition block sequence item yaml&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;./music-assistant-server/data:/data/&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line number-sign yaml&quot;&gt;&lt;span class=&quot;punctuation definition comment line number-sign yaml&quot;&gt;#&lt;/span&gt; privileged caps (and security-opt) needed to mount
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line number-sign yaml&quot;&gt;&lt;span class=&quot;punctuation definition comment line number-sign yaml&quot;&gt;#&lt;/span&gt; smb folders within the container
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;cap_add&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation definition block sequence item yaml&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;SYS_ADMIN&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation definition block sequence item yaml&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;DAC_READ_SEARCH&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;security_opt&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation definition block sequence item yaml&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;apparmor:unconfined&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;environment&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation definition block sequence item yaml&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;LOG_LEVEL=info&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line number-sign yaml&quot;&gt;&lt;span class=&quot;punctuation definition comment line number-sign yaml&quot;&gt;#&lt;/span&gt; And home assistant and other things.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add providers&lt;/p&gt;
&lt;p&gt;A provider is a source of music.
There’s a bunch of them but at the moment I only use a few:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/ma_spotify.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The Spotify provider for example should automatically sync all Spotify playlists into &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; and allows you to search and play any song on Spotify.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;Radio stations from RadioBrowser won’t show up automatically.
You first have to find them under the &lt;code&gt;Browse&lt;/code&gt; tab and add them to the library, then they’ll appear in the &lt;code&gt;Radio&lt;/code&gt; tab.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add players&lt;/p&gt;
&lt;p&gt;We need players to play our music, here’s what I currently use:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/ma_players.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The players should be automatically added as long as they have a matching provider enabled.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Quite a few different providers are supported.
I could even add our Sonos speaker as a player and we managed to once more listen to the radio on it.
Rejoice!&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Open-source music management—particularly on Linux—has a reputation of being notoriously troublesome.
But I’ve gotta say, &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; was simple to setup and it works well (except issues with some players that I’ll get to shortly).&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Trying-out-different-players&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Trying-out-different-players&quot; class=&quot;heading-ref&quot;&gt;Trying out different players&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was fairly lost in what kind of amplifier and music player I should get.&lt;/p&gt;
&lt;p&gt;There’s a lot of options out there but I was worried about paying a lot of money for something I wasn’t sure it would integrate well into my smart home setup.
Here’s a few options I’ve tried:&lt;/p&gt;
&lt;section id=&quot;Sonos&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Sonos&quot; class=&quot;heading-ref&quot;&gt;Sonos&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/sonos.jpg&quot;&gt;
&lt;figcaption&gt;The Sonos speaker has found new life in our washing room.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It’s pretty funny, the Sonos speaker works better with &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; than with the Sonos app.
The radio completely stopped working via the Sonos app, while I can use &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; to play the radio on the Sonos speaker.&lt;/p&gt;
&lt;p&gt;The speaker might still disconnect or stop playback at odd times but it’s good enough to raise the mood in the washing room.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Squeezelite-on-Linux&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Squeezelite-on-Linux&quot; class=&quot;heading-ref&quot;&gt;Squeezelite on Linux&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/living_room_speakers.jpg&quot;&gt;
&lt;figcaption&gt;Our living room setup with a TV, game consoles, speakers, a dumb amplifier, and a computer running Void Linux.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I hate modern smart TVs with a passion so to stream we use a computer running Linux, connected to a dumb amplifier with some speakers.
It works well but it makes it a bit more cumbersome to play music.&lt;/p&gt;
&lt;p&gt;By installing &lt;a href=&quot;https://github.com/ralph-irving/squeezelite&quot;&gt;Squeezelite&lt;/a&gt; the computer acts as a squeezebox client, effectively transforming it into a smart player for &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; and &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; to stream music to.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I started out by doing this on my work desktop too but since then &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; has added the ability to stream via the web interface, much like if you visit &lt;a href=&quot;https://open.spotify.com/&quot;&gt;https://open.spotify.com/&lt;/a&gt; in your browser.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;A-HifiBerry-player&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#A-HifiBerry-player&quot; class=&quot;heading-ref&quot;&gt;A HifiBerry player&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/hifiberry_pi.jpg&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;https://www.hifiberry.com/shop/boards/dealing-with-blocked-p5-holes-7/&quot;&gt;HifiBerry AMP2&lt;/a&gt; on top of a Raspberry Pi 3, acting as the amplifier and smart music controller. All you need is to connect the passive speakers.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;As I had a Raspberry Pi lying around it made sense to try the &lt;a href=&quot;https://www.hifiberry.com/shop/boards/dealing-with-blocked-p5-holes-7/&quot;&gt;HifiBerry AMP2&lt;/a&gt; that transforms the Pi into a surprisingly capable amplifier and smart music controller.
For simplicity I decided to start with their operating system &lt;a href=&quot;https://www.hifiberry.com/hifiberryos/&quot;&gt;HifiBerryOS&lt;/a&gt; that hopefully should “just work” and be open enough for me to manually fix things if needed.&lt;/p&gt;
&lt;p&gt;While it works very well as a Spotify Connect device or to play over Bluetooth I had issues with it acting as a Squeezelite or Airplay client as the &lt;a href=&quot;https://github.com/hifiberry/hifiberry-os/issues/529&quot;&gt;volume was super low&lt;/a&gt; when I tried to stream to it from &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It &lt;em&gt;might&lt;/em&gt; be a software issue with &lt;a href=&quot;https://www.hifiberry.com/hifiberryos/&quot;&gt;HifiBerryOS&lt;/a&gt; but I haven’t had the energy to debug it or try other OS versions.
Maybe I’ll revisit it when I want to outfit another room with speakers.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I ran into an issue where the Spotify mobile app got stuck at “Connecting” when I tried to play to HifiBerry.&lt;/p&gt;
&lt;p&gt;This &lt;a href=&quot;https://github.com/ashthespy/Vollibrespot/issues/13&quot;&gt;was an issue with a static DNS entry&lt;/a&gt;.
To &lt;a href=&quot;https://github.com/ashthespy/Vollibrespot/issues/13#issuecomment-2481246915&quot;&gt;fix it&lt;/a&gt; I had to remove &lt;code&gt;ap-gew4.spotify.com&lt;/code&gt; from &lt;code&gt;/etc/hosts&lt;/code&gt; on the device.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Arylic-A50&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Arylic-A50&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://www.arylic.com/products/arylic-a50-wifi-bluetooth-multiroom-full-digital-hifi-amplifier-with-airplay-dlna-multiroom-control&quot;&gt;Arylic A50+&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/arylic.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I was planning to use the HifiBerry to power two new speakers in the ceiling in the kitchen to replace the Sonos.
But I got stressed out by the &lt;a href=&quot;#A-HifiBerry-player&quot;&gt;HifiBerry not working properly&lt;/a&gt; and the kitchen renovation was looming ever closer so I bought the &lt;a href=&quot;https://www.arylic.com/products/arylic-a50-wifi-bluetooth-multiroom-full-digital-hifi-amplifier-with-airplay-dlna-multiroom-control&quot;&gt;Arylic A50+&lt;/a&gt;, hoping that it would work better with &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The device supports both Airplay and Squeezebox like the HifiBerry but again there were some issue with the volume being very low.
I don’t know if both devices just happen to have similar bugs, if there’s a bug with &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt;, or if it’s some weird compatibility issue.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sigh.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But there’s another way to make it work;
the Arylic has an excellent &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; integration and if you go that way
then &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; can use the Arylic as a player properly.
You need the LinkPlay integration in &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; and then enable the &lt;a href=&quot;#Home-Assistant-integration&quot;&gt;Home Assistant integration&lt;/a&gt; in &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(I tried the same with the HifiBerry integration but for some reason the HifiBerry media player exposed from Home Assistant didn’t show up in &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt;.)&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;The Arylic has a bunch of other integrations such as Bluetooth and Spotify Connect.
This is great as it allows my girlfriend to use Spotify on her phone to control the new speakers in the kitchen, exactly like how she used to control Sonos.&lt;/p&gt;
&lt;p&gt;If the spouse approves of your smart home shenanigans then you know you’ve done a good job.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Home-Assistant-integration&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Home-Assistant-integration&quot; class=&quot;heading-ref&quot;&gt;Home Assistant integration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; integrates well with &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;.
Setup is straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add the &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; integration in &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/ma_ha.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;This will expose all players in &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; to &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; (such as the Squeezebox players running on Linux).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable the &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; plugin in &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/ma_plugins.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;This will expose all media players in &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; to &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; (such as the Arylic or the &lt;a href=&quot;https://www.home-assistant.io/voice-pe/&quot;&gt;Home Assistant Voice Preview Edition&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With this setup you can setup Home Assistant actions to start a particular radio station, add a media player card to start/stop playback, or simply give &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; access to more players.&lt;/p&gt;
&lt;section id=&quot;In-Home-Assistant-how-do-you&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#In-Home-Assistant-how-do-you&quot; class=&quot;heading-ref&quot;&gt;In Home Assistant how do you…&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Play the &lt;code&gt;P4 Norrbotten&lt;/code&gt; radio station?&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;yaml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight yaml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;music_assistant.play_media&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;entity_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;media_player.kitchen&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;data&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;media_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;P4 Norrbotten&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Play the &lt;code&gt;To Hell and Back&lt;/code&gt; track?&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;yaml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight yaml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;music_assistant.play_media&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;entity_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;media_player.kitchen&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;data&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;media_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;To Hell and Back&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;media_type&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;track&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Play the &lt;code&gt;kpop&lt;/code&gt; playlist?&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;yaml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight yaml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;music_assistant.play_media&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;entity_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;media_player.kitchen&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;data&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;media_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;kpop&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;media_type&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;playlist&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Play the &lt;code&gt;kpop&lt;/code&gt; playlist randomized?&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;yaml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight yaml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;media_player.shuffle_set&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;entity_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation definition block sequence item yaml&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;media_player.kitchen&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;data&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;shuffle&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant language boolean yaml&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;action&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;music_assistant.play_media&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;target&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;entity_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;media_player.kitchen&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;data&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;media_id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;kpop&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;media_type&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;playlist&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;&lt;span class=&quot;entity name tag yaml&quot;&gt;enqueue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value mapping yaml&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string unquoted plain out yaml&quot;&gt;replace&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You get the new &lt;code&gt;music_assistant.play_media&lt;/code&gt; action but otherwise you control the media players just as the other media player entities in &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Its-not-perfect&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Its-not-perfect&quot; class=&quot;heading-ref&quot;&gt;It’s not perfect&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; is a fairly young open source project so minor bugs are to be expected.
There are also two larger feature that I miss:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I’d like to have access to my library even when I’m away from home.
Maybe &lt;a href=&quot;https://github.com/orgs/music-assistant/discussions/1834&quot;&gt;an Android app&lt;/a&gt; with native volume controls, notifications, and support for offline listening?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A better widget for &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/music_assistant/mini_media_player.png&quot;&gt;
&lt;figcaption&gt;The mini media player card.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;For basic sound controls in the kitchen I use the &lt;a href=&quot;https://github.com/kalkih/mini-media-player&quot;&gt;Mini Media Player&lt;/a&gt; card
but I’d like a better way to filter through playlists and music via the &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt; Lovelace UI.
I currently embed the &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; dashboard itself via an iframe but the UI is a bit too clunky for the size of my tablet.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Whats-next&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Whats-next&quot; class=&quot;heading-ref&quot;&gt;What’s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Still, I must admit, I’m stoked about finding a smarter way to control music throughout our house and I’m searching for an excuse to expand the setup in the future.
Here are some ideas I have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Speakers in the kid’s room to play music or audio books before they go to sleep.
&lt;/li&gt;
&lt;li&gt;
More music in my exercise space (it kind of works if I increase the volume of my office speakers, but it’s not ideal).
&lt;/li&gt;
&lt;li&gt;
A proper Hi Fi setup for true music enjoyment somewhere in the house.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite some integration issues and us not using &lt;a href=&quot;https://www.music-assistant.io/&quot;&gt;Music Assistant&lt;/a&gt; to it’s fullest potential it has still improved our setup in a major way.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Why I&apos;m back to Whoop (for now)</title><id>http://jonashietala.se/blog/2025/06/02/why_im_back_to_whoop_for_now/index.html</id><updated>2025-06-02T11:55:00+00:00</updated><link href="https://www.jonashietala.se/blog/2025/06/02/why_im_back_to_whoop_for_now" rel="alternate"/><published>2025-06-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I recently started to subscribe to &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; again after I canceled it around a year ago.
I was partly dissatisfied with my &lt;a href=&quot;https://www.garmin.com/en-US/p/884585/&quot;&gt;Garmin watch&lt;/a&gt; as a fitness and health tracker and I also wanted a new tech device to tinker with.&lt;/p&gt;
&lt;p&gt;The plan was to write a short post about what I like and don’t like about &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; but as usual I’m struggling with writing shorter posts.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If I had more time I would write a shorter letter.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Attributed to Blaise Pascal
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;The TLDR is that &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; is still expensive and imperfect;
yet it’s the most helpful smart device I’ve used
and a &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; in your underwear is the best way to track your heart rate while hugging spandex-wearing adults.&lt;/p&gt;
&lt;section id=&quot;A-brief-history-of-my-experiences-with-smart-devices&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#A-brief-history-of-my-experiences-with-smart-devices&quot; class=&quot;heading-ref&quot;&gt;A brief history of my experiences with smart devices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m not an elite athlete, not even close;
I’m just a programmer who struggles to stay active.
As I also like to play with tech I’ve tried out various smart devices in the hopes that they can help me to live a healthier life
(with various levels of success).&lt;/p&gt;
&lt;p&gt;Here’s the devices I’ve used, in purchase order:&lt;/p&gt;
&lt;div class=&quot;timeline &quot;&gt;&lt;div class=&quot;events&quot;&gt;
&lt;div class=&quot;event smartband&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Fitbit, -2020&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I had some smartband from Fitbit that I liked.
When that bugged out I bought the &lt;a href=&quot;https://www.theverge.com/2018/3/26/17163210/fitbit-versa-smartwatch-review-wearable-tech-apple-watch&quot;&gt;Fitbit Versa&lt;/a&gt;, with a square display.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event oura&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Oura ring, 2020-2021&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I wanted to track my sleep better, so I bought &lt;a href=&quot;https://ouraring.com/&quot;&gt;a ring&lt;/a&gt;.
It worked well.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event smartband&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Garmin Venu Sq, 2020-2023&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;The Fitbit kept disconnecting, so I abandoned it for a &lt;a href=&quot;https://www.garmin.com/sv-SE/p/707174/&quot;&gt;Garmin&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event oura&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Oura ring Gen 3, 2021-2023&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I had to recharge the ring all the time so I upgraded to the newer version.
(The battery of the new ring also deteriorated and I stopped using it when I had to charge it every 1–3 days.)&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event withings&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Withings Body+, 2022-&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I wanted to track my weight so I bought &lt;a href=&quot;https://www.withings.com/se/se/body-plus&quot;&gt;a smart scale&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event hrtracker&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Polar Verity Sense, 2022-2023&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I can’t track my Submission Grappling training with a watch or a ring,
so I bought &lt;a href=&quot;https://www.polar.com/en/products/accessories/polar-verity-sense&quot;&gt;a heart rate monitor&lt;/a&gt; you put on the bicep.
It was okay.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event smartwatch&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Fossil Gen 6 Wellness Edition, 2022&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Maybe I should try a &lt;em&gt;real&lt;/em&gt; &lt;a href=&quot;https://www.theverge.com/23511584/fossil-gen-6-wellness-edition-review-wear-os-smartwatch&quot;&gt;smartwatch&lt;/a&gt; with lots of smart features…?
I use Android so maybe a watch with WearOS is good?&lt;/p&gt;
&lt;p&gt;Jokes on me, WearOS was garbage and having to charge the watch every day is a nightmare.
I went back to the Garmin.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event smartwatch&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Garmin vivosmart 5, 2023-2024&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I wasn’t happy with the &lt;a href=&quot;https://www.garmin.com/sv-SE/p/707174/&quot;&gt;Garmin Venu Sq&lt;/a&gt; (can’t remember why) and disappointed with smart watches I figured &lt;a href=&quot;https://www.garmin.com/sv-SE/p/782585/&quot;&gt;a simple smart band&lt;/a&gt; would suffice.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event whoop&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Whoop 4.0, 2023-2024&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;The battery of my &lt;a href=&quot;https://ouraring.com/&quot;&gt;Oura&lt;/a&gt; was failing again so I tried &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; for a year.
Tracking Submission Grappling with a device in my underwear is so next level!&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event smartwatch&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Garmin Instinct 2X Solar, 2024-&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Charging the devices got annoying; I found the &lt;a href=&quot;https://www.garmin.com/en-US/p/884585/&quot;&gt;Garmin Instinct&lt;/a&gt;
you only charge once a month and it comes with a &lt;em&gt;flashlight&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Seriously, you haven’t truly lived before you’ve had a flashlight on your watch—it’s glorious.
(Jokes aside, it’s awesome.)&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event eightsleep&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Eight Sleep Pod 4, 2024&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Sleep is important so &lt;a href=&quot;/blog/2024/10/05/trying_and_returning_the_eight_sleep_pod_4/&quot;&gt;I tried (and returned) a ludicrously expensive smart mattress&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event whoop&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Whoop MG, 2025&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I was feeling down and I needed something to help me get back to prioritizing fitness and health,
and I just happened to check back on &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; right when Whoop MG was released…&lt;/p&gt;
&lt;p&gt;So I threw financial responsibility out the window and ordered the MG on release day.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Gosh, I’ve been good about not changing my phone that often but I didn’t realize I’ve wasted so much time and money on smart devices…&lt;/p&gt;
&lt;p&gt;Anyway, I’m currently using the &lt;a href=&quot;https://www.garmin.com/en-US/p/884585/&quot;&gt;Garmin Instinct 2X Solar&lt;/a&gt; as a “don’t glance at my phone” device and &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; as my fitness and health tracker,
ignoring the Garmin’s health and fitness tracking features.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-point-is-to-change-behaviours&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-point-is-to-change-behaviours&quot; class=&quot;heading-ref&quot;&gt;The point is to change behaviours&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While it’s fun to play with new things,
the main point of these smart devices is to (hopefully) help me change my behaviours in a positive way.
It doesn’t matter if the device is super accurate or produces the most beautiful graphs God has created;
if it doesn’t help me do things differently then the device is a failure.&lt;/p&gt;
&lt;p&gt;Here are two examples:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;My first Fitbit smartband was great.&lt;/p&gt;
&lt;p&gt;It’s true that it was quite limited in what it could do,
the tracking of steps/calories/steps/etc was wildly inaccurate,
and it disconnected from my phone &lt;em&gt;all the time&lt;/em&gt; making notifications completely unreliable.&lt;/p&gt;
&lt;p&gt;However, it presented the daily steps/calories/steps as pretty bars on the screen—bars that I should fill over the course of the day—and that caused me to move more than I’d have done otherwise.&lt;/p&gt;
&lt;p&gt;(This is a feature in most smartwatches today but nothing I’ve tried captured the feeling as well as my very first Fitbit device.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.garmin.com/en-US/p/884585/&quot;&gt;Garmin Instinct&lt;/a&gt; is useful, but not as a fitness or health device.&lt;/p&gt;
&lt;p&gt;I think the watch is very nice;
it’s got a fantastic battery life,
it’s not bothering me when I sleep,
I don’t have to reach for my phone to see if I have any notifications,
and the flashlight is &lt;em&gt;amazing&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It [the flashlight] is just super effin’ functional and useful day-to-day, with just as much utility as the flashlight on your phone (if not more, since your hands are still free).&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://www.dcrainmaker.com/2023/05/flashlight-multiband-everyone.html&quot;&gt;DCRainmaker&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Garmin also has lots of various measurements (and with much more accuracy than my old Fitbit);
I can see the daily steps;
I can follow how my “body battery” is doing;
I can track walks or runs very well (although I don’t run);
and I can follow my stress and heart rate throughout the day…&lt;/p&gt;
&lt;p&gt;But that doesn’t &lt;em&gt;do&lt;/em&gt; anything for me.
I have all these bars and graphs and circles on the watch that I should fill to meet my daily step count for example… But I just don’t.
Maybe my neanderthal brain needs more colors or something.&lt;/p&gt;
&lt;p&gt;The Garmin app is also not designed in a way to help me get motivated.
Maybe it’s more geared towards runners
or athletes that already train hard every day,
instead of middle-aged programmers who need that extra push to get out there?&lt;/p&gt;
&lt;p&gt;For whatever reason, as a device to improve my fitness and health, the Garmin is a failure.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-I-left-Whoop-last-year&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-I-left-Whoop-last-year&quot; class=&quot;heading-ref&quot;&gt;Why I left Whoop last year&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;About a year ago I chose to not renew my Whoop subscription and I &lt;a href=&quot;https://www.reddit.com/r/whoop/comments/1e1hzbe/today_i_cancelled_my_whoop_subscription_let_me/&quot;&gt;made a post on Reddit&lt;/a&gt; explaining why.&lt;/p&gt;
&lt;p&gt;Here’s a quick summary of my issues with &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If I had the Whoop in my boxers it thinks I’m sleeping when I sit in front of the computer or lie in the sofa.&lt;br&gt;
(This is still a big issue.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No custom insights for the journal.&lt;br&gt;
(Still nothing.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The UI for the strength trainer portion of the app sucked.&lt;br&gt;
(You can now add exercises after the training—a big step forward.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It’s too expensive if all it provides is tracking for Submission Grappling.&lt;br&gt;
(I realized I’m missing some of the other stuff.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;What-made-me-change-my-mind&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#What-made-me-change-my-mind&quot; class=&quot;heading-ref&quot;&gt;What made me change my mind?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When I quit &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; I was in a pretty good place in my life; I was feeling good, I was training consistently, and
I didn’t need external stimuli to keep going.&lt;/p&gt;
&lt;p&gt;But things have been different recently.
I’ve been &lt;a href=&quot;/blog/2023/03/14/battling_burnout&quot;&gt;struggling with depression&lt;/a&gt;, haven’t been able to get back to a regular training routine,
and I feel that I need all help I can get to get back on track.&lt;/p&gt;
&lt;p&gt;During the 10 months without &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; I relied on &lt;a href=&quot;https://www.garmin.com/en-US/p/884585/&quot;&gt;my Garmin watch&lt;/a&gt;
and I realized that the watch simply wasn’t helping me to improve my fitness or health the way I wanted from a smart device.&lt;/p&gt;
&lt;p&gt;I looked at alternatives but in the end I couldn’t find an alternative that matched &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt;’s feature set, so here I am.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;Please don’t think that any smart device can replace professional help.
I use these devices as a complement to, not in place of, a therapist and a coach.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Whoop-screwed-over-their-customers&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Whoop-screwed-over-their-customers&quot; class=&quot;heading-ref&quot;&gt;Whoop screwed over their customers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It was an interesting feeling to visit &lt;a href=&quot;https://www.reddit.com/r/whoop&quot;&gt;r/whoop&lt;/a&gt; after having placed my order
and see it overrun by people extremely upset about how &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; was treating their existing subscribers.&lt;/p&gt;
&lt;p&gt;I agree that &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; displayed some real corporate bullshit by telling people to pay an upgrade fee despite claiming for years that upgrades would be free (then walking back on the upgrade fee somewhat),
claiming that the 6-month subscription requirement for new hardware was “a mistake on their blog”,
and by breaking compatibility with the 4.0 bands.&lt;/p&gt;
&lt;p&gt;Some people claim that &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; broke the band compatibility intentionally but as I’ve experienced the same at work I think incompetence is more likely.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t want to be constrained by the old design!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Programmer, before corporate disaster
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;It sucks but corporations screwing us over in various ways is more or less expected.
This whole situation made me regret resubscribing to &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; immediately, before letting the dust settle.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Thoughts-on-Whoop-in-2025&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Thoughts-on-Whoop-in-2025&quot; class=&quot;heading-ref&quot;&gt;Thoughts on Whoop in 2025&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here are my first impressions after using the &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop MG&lt;/a&gt; for almost a month after resubscribing.&lt;/p&gt;
&lt;section id=&quot;Battery-life-is-excellent&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Battery-life-is-excellent&quot; class=&quot;heading-ref&quot;&gt;Battery life is excellent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some people don’t mind charging their devices a few times a week but I personally loath it.
With the new &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; and its battery life of ~2 weeks I can finally leave the battery pack when I go on my one week work trips and it’s &lt;em&gt;super nice&lt;/em&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-app-UI-is-great&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#The-app-UI-is-great&quot; class=&quot;heading-ref&quot;&gt;The app UI is great&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Maybe it’s “just” pretty UI but I find Whoop’s presentation much more helpful than the rawer presentation that Garmin has.&lt;/p&gt;
&lt;p&gt;For example I’ve always liked to look at sleep information ever since I started wearing an &lt;a href=&quot;https://ouraring.com/&quot;&gt;Oura ring&lt;/a&gt; and
&lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt;’s (recently redesigned) presentation is very good as it focuses on actionable metrics:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/whoop/whoop_sleep.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/whoop_sleep.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/whoop/garmin_sleep.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/garmin_sleep.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Whoop to the left focuses on metrics that I can change
while Garmin to the right focuses on sleep stages that I have no idea how to influence.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I also think Whoop is immediately more useful than Garmin’s when you open it up:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/whoop/whoop_start.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/whoop_start.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/whoop/garmin_start.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/garmin_start.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Whoop’s landing page to the left and Garmin’s on the right.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/whoop/strain_recovery.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/strain_recovery.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/whoop/hours_needed.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/hours_needed.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;I’m a sucker for pretty graphs and Whoop has a lot of them.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I have some gripes with the UI—I would like to be able to customize the home screen more for example—but overall I think Whoop’s app is a lot
better designed and more useful than any alternative I’ve tried.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;It’s been a few years since I last used &lt;a href=&quot;https://ouraring.com/&quot;&gt;Oura&lt;/a&gt; but from what I remember their app is also very good—just a shame that their exercise tracking is unusable for strength training and Submission Grappling.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Whoop-in-the-boxers&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Whoop-in-the-boxers&quot; class=&quot;heading-ref&quot;&gt;Whoop in the boxers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As I mentioned before, Whoop still thinks that I’m sleeping when I sit with Whoop in the boxers.
Either before I go to bed, after I go to bed, and sometimes it thinks I’m napping when I’m sitting during the day.&lt;/p&gt;
&lt;p&gt;Very annoying.&lt;/p&gt;
&lt;p&gt;But they’re still a killer feature for me because it’s the best way to track Submission Grappling.
&lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; is less accurate than the &lt;a href=&quot;https://www.polar.com/en/all-sensors&quot;&gt;Polar bicep/chest straps&lt;/a&gt;
but a biceps band or a chest strap sometimes gets in the way during training,
while I’ve never noticed the Whoop in my boxers.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/jones_sub.png&quot;&gt;
&lt;figcaption&gt;Submission grappling. A version of hugging where you try to strangle each other.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The Whoop 5.0 / MG also fits the 4.0 boxers well—lucky me as I have a bunch of the older 4.0 boxers.
I’ve gotta admit, I like their boxers and I kept using them even after I canceled my subscription.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/whoop/boxer_4.0.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/boxer_4.0.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/whoop/boxer_mg.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/boxer_mg.jpg&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;The Whoop MG in the 4.0 boxers to the left and the MG in the new boxers to the right.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I was skeptical to their new design with the “pods” but I think they’re an improvement as it’s a lot easier to add/remove the device while wearing the boxers,
and if you remove the pod they’re just like regular boxers.
The holders on my old 4.0 boxers have started to peel away and started to chafe but I think there’s less of a risk with the new design.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;ECG&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#ECG&quot; class=&quot;heading-ref&quot;&gt;ECG&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The ECG feature is why I went with Whoop MG instead of Whoop 5.0.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/whoop/ecg2.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/ecg2.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/whoop/ecg1.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/ecg1.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Outputs from Whoop’s ECG feature.
It’s a little difficult to take an ECG as you need to stay very still—you can see where I moved too much in the top-right picture.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve had a couple of episodes with chest pain where I’ve hurried to the hospital to get a check-up.
They never showed anything out of the ordinary (it was ruled as “something muscular”) but the experience has left me worried.&lt;/p&gt;
&lt;p&gt;If the ECG and background “Irregular Heart Rhytm” detection makes me relax a little (or if they do detect something) then I figured it’s worth the price jump from the 5.0 to the MG.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;Despite Whoop &lt;strong&gt;MG&lt;/strong&gt; hinting at &lt;strong&gt;M&lt;/strong&gt;edical &lt;strong&gt;G&lt;/strong&gt;rade I’m skeptical about it being medical grade as they make it clear that the neither the ECG nor background AFib detection provides a medical diagnosis.
Maybe it’s a marketing sleight of hand that they chose “MG” instead of “Medical Grade”…&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Whoop-age&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Whoop-age&quot; class=&quot;heading-ref&quot;&gt;Whoop age&lt;/a&gt;&lt;/h3&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/whoop/age1.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/age1.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/whoop/age2.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/age2.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;My “Whoop age” right after it unlocked after 3 weeks.
You can see that I’ve been exercising way to little and that I’m slightly overweight.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve seen Reddit warriors call the Whoop age metric a “gimmick” and dismiss it as just a combination of metrics available elsewhere.&lt;/p&gt;
&lt;p&gt;But for me—a middle-aged programmer dad who’s struggling to exercise consistently—the Whoop age metric is a fantastic addition to Whoop as it gives me a pretty &lt;em&gt;and actionable&lt;/em&gt; way to improve my overall health.&lt;/p&gt;
&lt;p&gt;I already know that I need to lose weight and exercise more, but sometimes you need someone else to hit you with the reality before you internalize the problem and start doing something about it.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;Aging faster might not matter that much &lt;em&gt;right now&lt;/em&gt;, but later in life feeling a few years younger instead of older can have a massive effect for your quality of life.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;It’s too early to tell how useful the Whoop age metric ultimately ends up being but my first impression is very positive.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;More-measures&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#More-measures&quot; class=&quot;heading-ref&quot;&gt;More measures&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Whoop also comes with more “raw” measures that I glance at from time to time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Body weight and body composition&lt;/p&gt;
&lt;p&gt;Whoop now syncs with my &lt;a href=&quot;https://www.withings.com/se/se/body-plus&quot;&gt;Withings smart scale&lt;/a&gt; and I do need to lose weight; it’s nice to have it in the Whoop app so I don’t have to open up Withing’s app just to see my weight trend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Steps&lt;/p&gt;
&lt;p&gt;Again, I have (more accurate) step tracking in Garmin but it’s nice to have it all in one app.
I try to hit a reasonable step goal and step counting—even if inaccurate—has made me try to move around more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VO&lt;sub&gt;2&lt;/sub&gt; MAX&lt;/p&gt;
&lt;p&gt;It seems like an important metric but I’m &lt;a href=&quot;https://www.youtube.com/watch?v=7zcXM1IYtqU&quot;&gt;not sure about it’s accuracy&lt;/a&gt; and it hasn’t caused me to change any behaviours.
(I also need to calibrate it with a 15 minutes run. I haven’t been on a run the last decade…)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blood pressure&lt;/p&gt;
&lt;p&gt;I calibrated the blood pressure insights but I’m not sure how useful it is for me.
Maybe it can act as an early indicator that my health is deteriorating but so far it’s just a pretty statistic.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Journaling-and-insights&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Journaling-and-insights&quot; class=&quot;heading-ref&quot;&gt;Journaling and insights&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The journal that correlates your behaviours with your recovery scores is an amazing feature and
&lt;em&gt;in theory&lt;/em&gt; this feature alone could carry a device such as Whoop by itself…&lt;/p&gt;
&lt;p&gt;If it wasn’t for the fact that the usefulness tapers off hard as soon as you learn how the various behaviours affect your body.
At the end of my last subscription I even turned off the journal as it didn’t provide any new information and filling it in only became a chore.&lt;/p&gt;
&lt;p&gt;Right now I use it but I only track a handful of behaviours that I want to remind myself of.
However, I’ll probably turn off the journal in a few months when the newness wears off again.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Bands&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Bands&quot; class=&quot;heading-ref&quot;&gt;Bands&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It was a really shitty move by &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; to break backwards compatibility with the old bands.
Granted, I don’t care that much about appearance so I never bought a lot of bands but I still want to switch between bands when they get wet after shower.&lt;/p&gt;
&lt;p&gt;Where corporations fails the 3D printer community steps up to save the day.
You can 3D print a &lt;a href=&quot;https://makerworld.com/en/models/1449870-whoop-5-0-mg-adapter?from=search#profileId-1510220&quot;&gt;whoop 5.0 / MG adapter&lt;/a&gt; to continue using your existing bands:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/whoop_4_arm.jpg&quot;&gt;
&lt;figcaption&gt;A 4.0 band together with my Whoop MG.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whoop/woop_4_adapter.jpg&quot;&gt;
&lt;figcaption&gt;A &lt;a href=&quot;https://makerworld.com/en/models/1449870-whoop-5-0-mg-adapter?from=search#profileId-1510220&quot;&gt;3D printed adapter&lt;/a&gt; making the 4.0 clasp compatible with a 5.0/MG device.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It’s not as secure as a proper 5.0/MG band and the old 4.0 battery doesn’t fit but it works well enough for regular usage (I don’t dare to swim with it).&lt;/p&gt;
&lt;p&gt;I’ll probably buy another band anyway so I have another ECG-compatible clasp; possibly a colorful &lt;a href=&quot;https://shop.whoop.com/en-eu/products/mg-sportflex-band/?sku=810114363560&quot;&gt;SportFlex&lt;/a&gt; band for when I swim with the kids.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; could’ve avoided so much backlash if they had given out an adapter to everyone who upgraded…&lt;/p&gt;
&lt;p&gt;The 5.0/MG release has quite a few lessons of things not to do when you release a new product.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Pricing&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Pricing&quot; class=&quot;heading-ref&quot;&gt;Pricing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Whoop outdid themselves and the MG took something already expensive and made it even more expensive.
While I don’t regret going with the more expensive option,
the “Peak” plan (without Blood pressure and ECG) probably makes more sense for most people.&lt;/p&gt;
&lt;p&gt;Still, if &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; can help me improve my fitness or health—even in a small way—the cost is worth it for me.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Conclusion&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Conclusion&quot; class=&quot;heading-ref&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Despite its faults and corporate bullshit, the &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; is still my favorite smart device for fitness and health.
I’ve tried to find alternatives but nothing has been as convenient or as helpful (or as expensive) as the Whoop.&lt;/p&gt;
&lt;p&gt;But the jury is still out on how helpful &lt;a href=&quot;https://www.whoop.com&quot;&gt;Whoop&lt;/a&gt; will be for me this time and in a year I may have moved on to try something else.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I’ve heard that some people sync the raw data from a ring, smartwatch, and heart rate monitor with an app, separating the data collection and data processing.
I haven’t tried that route yet but it sounds intriguing.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
</content></entry><entry><title>Some VORON 0 mods</title><id>http://jonashietala.se/blog/2025/05/02/voron_0_mods/index.html</id><updated>2026-04-27T15:25:12+00:00</updated><link href="https://www.jonashietala.se/blog/2025/05/02/voron_0_mods" rel="alternate"/><published>2025-05-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/zero_with_mods.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I recently completed &lt;a href=&quot;/blog/2025/03/25/lets_build_a_voron_0&quot;&gt;my VORON 0 build&lt;/a&gt; and I was determined to leave it as-is for a while and to start modding &lt;a href=&quot;/series/voron_trident&quot;&gt;my VORON Trident&lt;/a&gt;…&lt;/p&gt;
&lt;p&gt;So before embarking om my larger Trident modding journey I decided to work on the VORON 0 just a little bit more.&lt;/p&gt;
&lt;section id=&quot;HEPA-filter&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#HEPA-filter&quot; class=&quot;heading-ref&quot;&gt;HEPA filter&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/zero_back_open_with_filter.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;With the &lt;a href=&quot;https://github.com/nevermore3d/Nevermore_Micro&quot;&gt;Nevermore Micro V4&lt;/a&gt; I had active carbon filtering but I also wanted a HEPA filter that would also provide negative air pressure to the printer.
I found the &lt;a href=&quot;https://mods.vorondesign.com/details/tgFNVfEZGqjWbxWIt8ss2A&quot;&gt;Hepa filter by JNP&lt;/a&gt; for the VORON 0.1 and a &lt;a href=&quot;https://www.printables.com/model/878785-voron-0-top-back-panel-hepa-filter-by-jnp-mount&quot;&gt;mount for the VORON 0.2&lt;/a&gt; that I installed.&lt;/p&gt;
&lt;p&gt;For the fans I used two &lt;a href=&quot;https://noctua.at/en/products/fan/nf-a4x10-flx&quot;&gt;Noctua NF-A4x10 FLX&lt;/a&gt; fans and I spliced them together with the Nevermore filter, allowing the MCU to control all the filter fans together.
It might have been better to buy the 5V versions and connect them to the 5V output to have them always on, but by then I had already ordered the other version.
Oh well.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Back-meshed-panel&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Back-meshed-panel&quot; class=&quot;heading-ref&quot;&gt;Back meshed panel&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/zero_back_meshed.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The small 5V fan for the Raspberry Pi was super loud and I wanted to replace it with something.
Because the Raspberry Pi Zero doesn’t get that hot I removed the fan and replaced the back panel with &lt;a href=&quot;https://www.printables.com/model/1190744-voron-02-back-panel&quot;&gt;a meshed variant&lt;/a&gt;, which I hope should provide enough airflow to keep the electronics cool.&lt;/p&gt;
&lt;p&gt;(There are other variants with integrated fans if I realize this wasn’t enough.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Modesty-mesh&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Modesty-mesh&quot; class=&quot;heading-ref&quot;&gt;Modesty mesh&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/side_mesh.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The wiring is &lt;em&gt;super&lt;/em&gt; ugly and I stumbled upon the &lt;a href=&quot;https://mods.vorondesign.com/details/zQkxgPQUJw3HY5IHALTYA&quot;&gt;modesty mesh&lt;/a&gt; that hides the wires well from the sides.
Not at all necessary but they make the printer a little prettier.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Full-size-panels&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Full-size-panels&quot; class=&quot;heading-ref&quot;&gt;Full size panels&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/zero_with_mods.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;One thing that bothered me with the stock VORON 0.2 was the gaps between the tophat and the side panels and front door.
I went looking for a mod with fill-sized panels and found the &lt;a href=&quot;https://github.com/zruncho3d/ZeroPanels&quot;&gt;ZeroPanels mod&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instead of magnets the printed parts clips into the extrusions pretty hard while still allowing you to pull them off when you want to.
It works really well honestly.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/trident_print_zero_clip.jpg&quot;&gt;
&lt;figcaption&gt;The clips were slightly difficult to print but manageable.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I was looking at the &lt;a href=&quot;https://github.com/zruncho3d/BoxZero&quot;&gt;BoxZero mod&lt;/a&gt; for a proper full-sized panels mod but I didn’t want to tear apart the printer and rebuild the belt path so I simply replaced the stock panels with full sized ones.
This does leave some air gaps at the back and front of the printer right next to the belt that I simply covered with some tape:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/tape.jpg&quot;&gt;
&lt;figcaption&gt;Some tape to cover the gaps around the belts.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;While the clips are good for panels you don’t remove that often, they’re too much to use for the front door.
They have some magnetic clips you can use but I’m honestly perplexed on how to use them for good effect.&lt;/p&gt;
&lt;p&gt;The standard VORON 0 handles don’t consider the extra 3mm the foam tape adds, leaving a gap that severely reduces the pulling force of the magnets.
Similarly the magnet clips included in ZeroPanels surprisingly have the same issue.&lt;/p&gt;
&lt;p&gt;For the door handle I used the stealth handle found in the &lt;a href=&quot;https://www.printables.com/model/583082-voron-02-fullsize-zeropanel-mod-stock-frame-full-p/files&quot;&gt;Voron 0.2 fullsize ZeroPanel mod&lt;/a&gt; that does take the foam tape into consideration.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/clips.jpg&quot;&gt;
&lt;figcaption&gt;Three different magnet holders; at the top the Stealth handles holders that come out 3mm, in the middle the 6mm holder, and at the bottom the standard magnet holder.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There’s a &lt;a href=&quot;https://github.com/zruncho3d/ZeroPanels/pull/6&quot;&gt;variant of the clips for 6mm magnets&lt;/a&gt; in the pull requests that I used by pushing in two 3x2mm magnets and super gluing one 10x3mm magnet on top, so it sticks out the 3mm extra distance the foam tape adds. (Yes, maybe just the 10x3mm magnet would be enough).&lt;/p&gt;
&lt;p&gt;For the outside I used the standard &lt;a href=&quot;https://github.com/zruncho3d/ZeroPanels&quot;&gt;ZeroPanels&lt;/a&gt; holders for 10x3mm magnets, allowing the magnets close really tightly against each other.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0_mods/magnets_top.jpg&quot;&gt;
&lt;figcaption&gt;Extra magnets at the top of the printer to get a proper seal.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;The panels I bought were just &lt;em&gt;slightly&lt;/em&gt; too wide causing the side panels to bend a little and it made it hard to get a close seal for front and side panels.
I had to file down the clips on the front door to avoid them from colliding with the side panel clips, and I had to add extra clips and magnets for the panels to close tightly against the foam tape.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s build a VORON 0</title><id>http://jonashietala.se/blog/2025/03/25/lets_build_a_voron_0/index.html</id><updated>2026-01-29T10:45:13+00:00</updated><link href="https://www.jonashietala.se/blog/2025/03/25/lets_build_a_voron_0" rel="alternate"/><published>2025-03-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/completed_front.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;About 1.5 years ago I ventured into 3D printing by &lt;a href=&quot;/series/voron_trident/&quot;&gt;building a VORON Trident&lt;/a&gt;.
It was a very fun project and I’ve even used the printer quite a bit.&lt;/p&gt;
&lt;p&gt;Naturally, I had to build another one and this time I opted for the cute &lt;a href=&quot;https://vorondesign.com/voron0.2&quot;&gt;VORON 0&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;Why-another-printer&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-another-printer&quot; class=&quot;heading-ref&quot;&gt;Why another printer?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I really like my &lt;a href=&quot;/series/voron_trident/&quot;&gt;VORON Trident&lt;/a&gt; and it’ll continue to be my main printer for the foreseeable future but a second printer would do two important things for me:&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;Act as a backup printer if my Trident breaks.&lt;/p&gt;
&lt;p&gt;A printer made partially of printed parts is great as you can easily repair it…
But only if you have a working printer to print the parts.&lt;/p&gt;
&lt;p&gt;It would also be very annoying if I disassemble the printer because I want to mod it and realize I’ve forgotten to print a part I needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Building printers are &lt;em&gt;really fun&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/series/voron_trident/&quot;&gt;Building the VORON Trident&lt;/a&gt; is one of my most fun and rewarding projects I’ve done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-a-VORON-0&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-a-VORON-0&quot; class=&quot;heading-ref&quot;&gt;Why a VORON 0?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These properties makes the VORON 0 an ideal secondary printer for me:&lt;/p&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
&lt;p&gt;You need to assemble the VORON 0 yourself (a feature not a bug)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Prints ABS/ASA well (for printer parts)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Very moddable and truly open source&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It’s tiny&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/zero_and_trident.jpg&quot;&gt;
&lt;figcaption&gt;The VORON 0 to the left and the VORON Trident 250 to the right.
It’s really small, which is perfect for me as I have a limited amount of space.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It would be very fun to build a VORON 2.4 (or even a VORON Phoenix) but I really don’t have space for more printers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Getting-the-parts&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Getting-the-parts&quot; class=&quot;heading-ref&quot;&gt;Getting the parts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I opted to buy a kit instead of self-sourcing the parts as it’s usually cheaper and requires a lot less work, even if you replace some parts.&lt;/p&gt;
&lt;p&gt;This is what I ended up getting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A VORON 0 kit from &lt;a href=&quot;https://lecktor.com/en/&quot;&gt;Lecktor&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Parts for a &lt;a href=&quot;https://github.com/chirpy2605/voron/tree/main/V0/Dragon_Burner&quot;&gt;Dragon Burner&lt;/a&gt; toolhead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Parts for a &lt;a href=&quot;https://github.com/nevermore3d/Nevermore_Micro&quot;&gt;Nevermore V4&lt;/a&gt; active carbon filter&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Later on, I replaced the SKR Mini E3 V2 that came with the kit with the V3&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;section id=&quot;Lots-of-delays&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Lots-of-delays&quot; class=&quot;heading-ref&quot;&gt;Lots of delays&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I ordered a VORON 0 from &lt;a href=&quot;https://lecktor.com/en/&quot;&gt;Lecktor&lt;/a&gt; in February 2024 and it took roughly 4 months before I got the &lt;em&gt;first&lt;/em&gt; shipment of parts and it wasn’t until the end of 2024 that I had received all the parts needed to complete the build.&lt;/p&gt;
&lt;p&gt;The wait was &lt;em&gt;annoying&lt;/em&gt;…&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;While I can’t complain about the quality of parts, with the massive delays I regret ordering from &lt;a href=&quot;https://lecktor.com/en/&quot;&gt;Lecktor&lt;/a&gt; and in hindsight I should’ve ordered an LDO kit from &lt;a href=&quot;https://www.3djake.com/&quot;&gt;3DJake&lt;/a&gt;, like I was first considering.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Printing-parts-myself&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Printing-parts-myself&quot; class=&quot;heading-ref&quot;&gt;Printing parts myself&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So what do you do when you can’t start the build?&lt;/p&gt;
&lt;p&gt;You print parts!&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/box_of_parts.jpg&quot;&gt;
&lt;figcaption&gt;A box of some of the printed parts for the build (and many I later threw away).
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There’s something very satisfying with printing parts you then build a printer with.&lt;/p&gt;
&lt;p&gt;This time I wanted to make a colorful printer and I came up with this mix of filament:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.3djake.com/polymaker/polylite-asa-yellow&quot;&gt;PolyLite ASA Yellow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.3djake.com/formfutura/easyfiltm-abs-light-green&quot;&gt;Formfutura EasyFil ABS Light Green&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.3djake.com/formfutura/easyfiltm-abs-light-blue&quot;&gt;Formfutura EasyFil ABS Light Blue&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.3djake.com/formfutura/easyfiltm-abs-magenta&quot;&gt;Formfutura EasyFil ABS Magenta&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think they made the printer look great.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;The-build&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-build&quot; class=&quot;heading-ref&quot;&gt;The build&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/office_overview2.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I won’t do as detailed of a build log as I did when &lt;a href=&quot;/series/voron_trident/&quot;&gt;building the VORON Trident&lt;/a&gt; but I tried to take some pictures.
Scroll on!&lt;/p&gt;
&lt;section id=&quot;Frames-and-bed&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Frames-and-bed&quot; class=&quot;heading-ref&quot;&gt;Frames and bed&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/assembly_start.jpg&quot;&gt;
&lt;figcaption&gt;The linear Y-rails.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/kirigami_assemblqu.jpg&quot;&gt;
&lt;figcaption&gt;The kit comes with the &lt;a href=&quot;https://github.com/christophmuellerorg/voron_0_kirigami_bed/&quot;&gt;Kirigami bed mod&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/frame.jpg&quot;&gt;
&lt;figcaption&gt;The frame with A/B motors.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/plate_upside_down.jpg&quot;&gt;
&lt;figcaption&gt;Building the bottom of the printer with feet, power supply, and display.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;MGN9-instead-of-MGN7-X-axis&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#MGN9-instead-of-MGN7-X-axis&quot; class=&quot;heading-ref&quot;&gt;MGN9 instead of MGN7 X-axis&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After I assembled the X-axis I noticed a problem:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/wrong_drive2.jpg&quot;&gt;
&lt;figcaption&gt;The carriage collides with the stock A drive.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The reason is that the kit comes with MGN9 rails for the X-axis instead of the standard MGN7 rails.
This required me to reprint modified A/B drives, X-carriage, and alignment tools.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/wrong_drive1.jpg&quot;&gt;
&lt;figcaption&gt;The carriage passes the modded B drive.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Belts&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Belts&quot; class=&quot;heading-ref&quot;&gt;Belts&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/belt_routing.jpg&quot;&gt;
&lt;figcaption&gt;Starting to install the belt.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/in_progress.jpg&quot;&gt;
&lt;figcaption&gt;The belt is &lt;strong&gt;tight&lt;/strong&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Dragon-Burner-toolhead&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Dragon-Burner-toolhead&quot; class=&quot;heading-ref&quot;&gt;Dragon Burner toolhead&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I got the parts needed to build the standard mini stealthburner…&lt;/p&gt;
&lt;p&gt;But I’m attracted to playing around with new stuff and I decided to try out the &lt;a href=&quot;https://github.com/chirpy2605/voron/tree/main/V0/Dragon_Burner&quot;&gt;Dragon Burner&lt;/a&gt; instead.
I went with it because it’s quite popular, it has good cooling (I print a bunch of PLA), and I haven’t tried it out yet.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/dragonburner_front.jpg&quot;&gt;
&lt;figcaption&gt;The fans are inserted.
I don’t care about LEDs so I inserted an opaque magenta part instead.
I think it looks really good.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Some friendly people over at the &lt;a href=&quot;https://forum.vorondesign.com/&quot;&gt;VORON forum&lt;/a&gt; and the Discord were quick to point out that I had installed the hotend fan wrong.
The fan is supposed to blow air towards the hotend, not away from it.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/nevermore_fan_ok.jpg&quot;&gt;
&lt;figcaption&gt;The hotend fan now correctly installed.
The sticker on this particular fan should be pointing inwards and shouldn’t be visible.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/dragonburner_back.jpg&quot;&gt;
&lt;figcaption&gt;The back of the Dragon Burner.
I opted for the &lt;a href=&quot;https://www.phaetus.com/products/rapido2&quot;&gt;Rapido 2&lt;/a&gt; instead of the &lt;a href=&quot;https://www.phaetus.com/products/dragon-hotend-hf&quot;&gt;Dragon&lt;/a&gt; that came with the kit because the &lt;a href=&quot;https://www.phaetus.com/products/dragon-hotend-hf&quot;&gt;Dragon&lt;/a&gt; has problems printing PLA.

&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/dragonburner_cable_back.jpg&quot;&gt;
&lt;figcaption&gt;I was a bit confused on how to route the wires as there was very little space when mounting the toolhead on the carriage.
Routing the wires close to the fans, clipping off the ears of the fans, and holding together it with cable ties in this way worked for me.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Galileo-2-standalone&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Galileo-2-standalone&quot; class=&quot;heading-ref&quot;&gt;Galileo 2 standalone&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/dragonburner_mounted.jpg&quot;&gt;
&lt;figcaption&gt;Dragon Burner together with the Galileo 2 extruder mounted on the printer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;For the extruder I opted for the standalone version of &lt;a href=&quot;https://github.com/JaredC01/Galileo2&quot;&gt;Galileo 2&lt;/a&gt;.
I’ve &lt;a href=&quot;/blog/2024/02/27/lets_build_a_voron_more_mods#Galileo-2&quot;&gt;used Galileo 2 on the Trident&lt;/a&gt; but I hated the push down latch it uses in the Stealthburner configuration.
The latch eventually broke by pulling out a heat-set insert so I went back to the Clockwork 2 on the Trident, giving me the parts to rebuilt the Galileo for the VORON 0 in a standalone configuration.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/galileo_standalone.jpg&quot;&gt;
&lt;figcaption&gt;The parts for Galileo 2. There will be left-overs from the Stealthburner variant.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The build was really fast and simple—compared to the Stealthburner variant it’s night and day.
I didn’t even think to take a break for pictures.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Nevermore-filter&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Nevermore-filter&quot; class=&quot;heading-ref&quot;&gt;Nevermore filter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since I want to be able to print ABS I feel I need to have an activated carbon filter.
I wanted to have an exhaust fan with a HEPA filter as well, but I’ll leave that to a mod in the future.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/nevermore3d/Nevermore_Micro&quot;&gt;Nevermore V4&lt;/a&gt; is an activated carbon filter that fits well in the VORON 0.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/nevermore_fan.jpg&quot;&gt;
&lt;figcaption&gt;I fastened the fan using a strip of VHB—it was a struggle to position it in the middle.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/nevermore_mounted.jpg&quot;&gt;
&lt;figcaption&gt;The Nevermore is mounted standing in the side of the printer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;Just remember to preload the extrusion with extra M3 nuts when you assemble the printer.
(I’ve heard LDO has nuts you can insert after… Sounds great.)&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Panels&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Panels&quot; class=&quot;heading-ref&quot;&gt;Panels&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/backplate.jpg&quot;&gt;
&lt;figcaption&gt;With the panel and spool holder at the back.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Please ignore the filament path in this picture, it’ll interfere with the rear belt when routed behind the umbilical cable.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/panels_tophat.jpg&quot;&gt;
&lt;figcaption&gt;With the tophat and door installed.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I’m slightly annoyed with the small gaps and holes the printer has (mainly between the tophat and the panels at the bottom half).&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I later changed some of the parts related to the top hat to match the colorscheme better.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Wiring&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Wiring&quot; class=&quot;heading-ref&quot;&gt;Wiring&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Wiring was simpler than for the &lt;a href=&quot;/series/voron_trident/&quot;&gt;Trident&lt;/a&gt; but it was harder to make the wiring pretty.
Thank god I could cover it up.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/bottom_wiring.jpg&quot;&gt;
&lt;figcaption&gt;The underside of the printer with the power, 5V converter, display, and Z-motor.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/back_wiring.jpg&quot;&gt;
&lt;figcaption&gt;Back of the printer with the Raspberry Pi and MCU.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;section id=&quot;Raspberry-Pi&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#Raspberry-Pi&quot; class=&quot;heading-ref&quot;&gt;Raspberry Pi&lt;/a&gt;&lt;/h4&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/pi_zero.jpg&quot;&gt;
&lt;figcaption&gt;The Raspberry Pi only has two cables; power and communication over the GPIO pins and a display via USB.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/tft_connection.jpg&quot;&gt;
&lt;figcaption&gt;The Pi communicates and gets power over the TFT connection on the MCU.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Toolhead&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#Toolhead&quot; class=&quot;heading-ref&quot;&gt;Toolhead&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The kit came with a toolhead board and breakout board for an umbilical setup:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/toolhead_board.jpg&quot;&gt;
&lt;figcaption&gt;The toolhead board.&lt;br&gt;
I didn’t use the x-endstop.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/umbilical_breakout_board.jpg&quot;&gt;
&lt;figcaption&gt;The breakout board.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I did run into an issue where the polarity of the fans on the toolhead board did not match the polarity of the fans on the MCU, leading to some frustration where the fans refused to spin.
I ended up swapping the polarity using the cables from the breakout board to the MCU.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Chamber-thermistor&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#Chamber-thermistor&quot; class=&quot;heading-ref&quot;&gt;Chamber thermistor&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The MCU only has two thermistor ports and they’re used for the hotend and bed thermistors.
For the chamber thermistor (that’s integrated into the breakout board) I use the MOSI pin on the SPI1 8-pin header:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/chamber_thermistor.jpg&quot;&gt;
&lt;figcaption&gt;The chamber thermistor connected to MOSI and ground on the SPI1 header.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;SKR-mini-E3-v3&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#SKR-mini-E3-v3&quot; class=&quot;heading-ref&quot;&gt;SKR mini E3 v3&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I got an SKR mini E3 v2 with the kit but I replaced it with the v3 for two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
An extra &lt;code&gt;FAN&lt;/code&gt; output, used for the Nevermore Filter
&lt;/li&gt;
&lt;li&gt;
A filament runout sensor
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There’s not much to say about the extra &lt;code&gt;FAN&lt;/code&gt; output but the filament runout sensor has 3 pins, while VORON 0.2 style runout sensor has 3 pins.
I reused the prepared y-endstop I got with the kit, scratched away some of the plastic to make the 2-pin connection fit the 3-pins on the MCU (the +5V pin isn’t needed):&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/filament_runout_sensor.jpg&quot;&gt;
&lt;figcaption&gt;The filament runout sensor connected to &lt;code&gt;E0-stop&lt;/code&gt;.&lt;br&gt;
Yes it’s not the right connector but where there’s a will there’s a way.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Klipper-setup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Klipper-setup&quot; class=&quot;heading-ref&quot;&gt;Klipper setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I followed the &lt;a href=&quot;https://docs.vorondesign.com/build/software/#software-installation&quot;&gt;VORON documentation&lt;/a&gt; and chose Mainsail as I’ve been happy with it on my Trident.
I’m not going to describe everything and only call out some issues I had or extra steps I had to take.&lt;/p&gt;
&lt;section id=&quot;MCU-firmware&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#MCU-firmware&quot; class=&quot;heading-ref&quot;&gt;MCU firmware&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.vorondesign.com/build/software/#software-installation&quot;&gt;VORON documentation&lt;/a&gt; assumes USB communication so the default firmware instructions didn’t work for me.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://github.com/bigtreetech/BIGTREETECH-SKR-mini-E3/blob/master/firmware/V3.0/Klipper/README.md&quot;&gt;BigTreeTech’s documentation&lt;/a&gt; if you communicate over USART2 (the TFT port) then you need to compile the firmware with &lt;code&gt;Communication interface&lt;/code&gt; set to &lt;code&gt;Serial (on USART2 PA3/PA2)&lt;/code&gt;.
You then need to use this klipper configuration:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[mcu]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;serial: /dev/ttyAMA0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;restart_method: command
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;It took a long time for me to figure out as I had a display connected via USB, so I thought the display was the MCU and got stuck at a &lt;code&gt;Your Klipper version is: xxx MCU(s) which should be updated: xxx&lt;/code&gt; error.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Filament-runout&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Filament-runout&quot; class=&quot;heading-ref&quot;&gt;Filament runout&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[filament_switch_sensor Filament_Runout_Sensor]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pause_on_runout: True
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;runout_gcode: PAUSE
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;switch_pin: PC15
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Chamber-thermistor-1&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Chamber-thermistor-1&quot; class=&quot;heading-ref&quot;&gt;Chamber thermistor&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;According to &lt;a href=&quot;https://github.com/bigtreetech/BIGTREETECH-SKR-mini-E3/issues/632#issuecomment-1383618898&quot;&gt;this comment&lt;/a&gt; this is the config to use the SPI header for a thermistor:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[temperature_sensor chamber_temp]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;sensor_type: Generic 3950
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;sensor_pin: PA7
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pullup_resistor: 10000
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Works for me™&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Display&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Display&quot; class=&quot;heading-ref&quot;&gt;Display&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It’s &lt;a href=&quot;https://forum.vorondesign.com/threads/voron-0-display-not-flashing.1641/&quot;&gt;easy to flash the display&lt;/a&gt; directly from the Raspberry Pi although the first firmware I built was too large.
There are optional features you can remove but I removed too many so the configuration for the buttons wasn’t accepted.
These were the features that ended up working for me:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[*] Support GPIO &quot;bit-banging&quot; devices
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[*] Support LCD devices
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[ ] Support thermocouple MAX sensors
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[ ] Support adxl accelerometers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[ ] Support lis2dw and lis3dh 3-axis accelerometers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[ ] Support MPU accelerometers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[*] Support HX711 and HX717 ADC chips
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[ ] Support ADS 1220 ADC chip
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[ ] Support ldc1612 eddy current sensor
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[ ] Support angle sensors
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[*] Support software based I2C &quot;bit-banging&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[*] Support software based SPI &quot;bit-banging&quot;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Sensorless-homing&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Sensorless-homing&quot; class=&quot;heading-ref&quot;&gt;Sensorless homing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I was nervous setting up sensorless homing, fearing that without a physical switch the printer might decide to burn the motor against the edge or something. (I really have no idea how it works, hence my fear.)&lt;/p&gt;
&lt;p&gt;In the end it was straightforward.
The &lt;a href=&quot;https://github.com/VoronDesign/Voron-0/tree/Voron0.2r1/Firmware&quot;&gt;VORON 0 example firmware&lt;/a&gt; was already configured for sensorless homing and the only things I had to do was:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Physically jump the &lt;code&gt;X-DIAG&lt;/code&gt; and &lt;code&gt;Y-DIAG&lt;/code&gt; pins on the board
&lt;/li&gt;
&lt;li&gt;
Tweak the &lt;code&gt;driver_SGTHRS&lt;/code&gt; values (I landed on &lt;code&gt;85&lt;/code&gt; down from &lt;code&gt;255&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And now I have sensorless homing working consistently.&lt;/p&gt;
&lt;p&gt;What confused me was that the &lt;a href=&quot;https://docs.vorondesign.com/tuning/sensorless.html&quot;&gt;sensorless homing guide&lt;/a&gt; and the &lt;a href=&quot;https://github.com/EricZimmerman/Voron02/blob/PreKlippain/macros/helpers/homing.cfg&quot;&gt;homing macros&lt;/a&gt; it links to were slightly different from the &lt;a href=&quot;https://github.com/VoronDesign/Voron-0/tree/Voron0.2r1/Firmware&quot;&gt;VORON 0 example firmware&lt;/a&gt; and it wasn’t clear if I had to make all the changes or not. (I did not.)&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Some-random-issues-I-encountered&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Some-random-issues-I-encountered&quot; class=&quot;heading-ref&quot;&gt;Some random issues I encountered&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In typical 3D printer fashion, you’ll always run into various issues, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I got the &lt;code&gt;mcu shutdown: Timer too close&lt;/code&gt; error a few times.&lt;/p&gt;
&lt;p&gt;I don’t know what I did but it only happened a couple of times at beginning.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The filament sensor had some consistency issues.&lt;/p&gt;
&lt;p&gt;Some extra tape on the bearing seemed to fix it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The filament keeps getting stuck in the extruder after unload.&lt;/p&gt;
&lt;p&gt;I’m still having issues but forgetting to tighten the nozzle and using a too short PTFE tube didn’t help.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I had trouble getting the filament to stick to bed.&lt;/p&gt;
&lt;p&gt;Super frustrating to be honest.
I re-calibrated the z offset and thumb screws a bunch of times and (right now) it seems to work fairly well.
Even though you’re not supposed to need automatic bed leveling for a printer this small, I can’t help but miss the “just works” feeling I have with the Trident.&lt;/p&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update &lt;span class=&quot;date&quot;&gt;2025-03-27&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;I absolutely recommend anyone to follow Elli’s &lt;a href=&quot;https://ellis3dp.com/Print-Tuning-Guide/articles/first_layer_squish.html&quot;&gt;First Layer Squish&lt;/a&gt; guide after you’ve tried to calibrate your bed screws and z endstop.
It’s much easier to see any minor inconsistencies visually than with the paper test and you’ll get much better bed adhesion (and prints) if you just take your time to tune in a good first layer squish.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Initial-thoughts-on-the-printer&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Initial-thoughts-on-the-printer&quot; class=&quot;heading-ref&quot;&gt;Initial thoughts on the printer&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/voron_0/dino_print.jpg&quot;&gt;
&lt;figcaption&gt;A model I printed for one of my kids. It came out really well.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I haven’t printed that much with the printer yet but I have some positive things to say about it:&lt;/p&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
It looks very good and was very fun to build.
&lt;/li&gt;
&lt;li&gt;
The small footprint is great and a surprising amount of prints fits on the small build volume.
&lt;/li&gt;
&lt;li&gt;
The print quality is very good. The extra cooling from the &lt;a href=&quot;https://github.com/chirpy2605/voron/tree/main/V0/Dragon_Burner&quot;&gt;Dragon Burner&lt;/a&gt; is great when printing PLA (which I use a lot).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;But I have some negative things to say too:&lt;/p&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
It’s loud. The 5V fan close to the Raspberry Pi is &lt;em&gt;horribly&lt;/em&gt; loud but the print movement is also too loud for my taste.
&lt;/li&gt;
&lt;li&gt;
It’s poorly insulated. For example there are gaps between the top hat and the rest of the printer that I don’t see a good way to cover up.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Overall though I’m very happy with it.
I wouldn’t recommend it as a first printer or to someone who just wants a tool that works out of the box,
but for people like me who wanted to build a backup/secondary printer I think it’s &lt;em&gt;great&lt;/em&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Whats-next&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Whats-next&quot; class=&quot;heading-ref&quot;&gt;What’s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With a secondary printer finally up and running I can now start working on some significant mods for my &lt;a href=&quot;/series/voron_trident/&quot;&gt;Trident&lt;/a&gt;!
This is the tentative plan right now:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Install the &lt;a href=&quot;https://mods.vorondesign.com/details/pXkXHVIUbqSWqQKJISczw&quot;&gt;Inverted electronics&lt;/a&gt; mod.
&lt;/li&gt;
&lt;li&gt;
Replace Stealthburner with another toolhead, most likely &lt;a href=&quot;https://github.com/Armchair-Heavy-Industries/A4T&quot;&gt;A4T-toolhead&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Build a &lt;a href=&quot;https://www.3djake.com/ldo-motors/boxturtle-v10&quot;&gt;BoxTurtle&lt;/a&gt; for multi-color support.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But we’ll see when I manage to get to it. I’m not in a rush and I should take a little break and play with my &lt;a href=&quot;https://vorondesign.com/voron0.2&quot;&gt;VORON 0&lt;/a&gt; and perhaps work on my other dozen or so projects that lie dormant.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>I&apos;ll give up Neovim when you pry it from my cold, dead hands</title><id>http://jonashietala.se/blog/2025/02/18/ill_give_up_neovim_when_you_pry_it_from_my_cold_dead_hands/index.html</id><updated>2025-02-18T11:25:38+00:00</updated><link href="https://www.jonashietala.se/blog/2025/02/18/ill_give_up_neovim_when_you_pry_it_from_my_cold_dead_hands" rel="alternate"/><published>2025-02-18T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I recently came upon a horror story where a developer was &lt;a href=&quot;https://www.reddit.com/r/neovim/comments/1iqvv60/my_workplace_mandated_cursor/&quot;&gt;forced to switch editor from Neovim to Cursor&lt;/a&gt;
and I felt I had to write a little to cleanse myself of the disgust I felt.&lt;/p&gt;
&lt;section id=&quot;Two-different-ways-of-approaching-an-editor&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Two-different-ways-of-approaching-an-editor&quot; class=&quot;heading-ref&quot;&gt;Two different ways of approaching an editor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think that there’s two opposing ways of thinking about the tool that is an editor:&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;Refuse to personalize anything and only use the basic features&lt;/p&gt;
&lt;p&gt;“&lt;em&gt;An editor is a simple tool I use to get the job done.&lt;/em&gt;”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get stuck in configuration hell and spend tons of time tweaking minor things&lt;/p&gt;
&lt;p&gt;“&lt;em&gt;An editor is a highly personalized tool that works the way I want.&lt;/em&gt;”&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are the extreme ends of the spectrum to make a point and most developers will fall somewhere in between.&lt;/p&gt;
&lt;p&gt;It’s not a static proposition; I’ve had periods in my life where I’ve used the same Vim configuration for years and other times I’ve spent more time rewriting my Neovim config than doing useful things.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I don’t differentiate between text editors and IDEs as I don’t find the distinction very meaningful.
They’re all just editors.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Freedom-of-choice-is-important&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Freedom-of-choice-is-important&quot; class=&quot;heading-ref&quot;&gt;Freedom of choice is important&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Freedom of choice is more to be treasured than any possession earth can give.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;David O. McKay
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some developers want zero configuration while others want to configure their editor so it’s &lt;em&gt;just&lt;/em&gt; right.
Either way is fine and I’ve met excellent developers from both sides.&lt;/p&gt;
&lt;p&gt;But removing the power of choice is a &lt;em&gt;horrible&lt;/em&gt; idea as you’re forcing developers to work in a way they’re not comfortable with, not productive with, or simply don’t like.
You’re bound to make some of the developers miserable or see them leave (usually the best ones who can easily find another job).&lt;/p&gt;
&lt;p&gt;To explain how important an editor might be to some people, I give you this story about Stephen Hendry—one of the most successful Snooker players ever—and how important his cue was to him:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In all the years I’ve been playing I’ve never considered changing my cue. It was the first cue I ever bought, aged 13, picked from a cabinet in a Dunfermline snooker centre just because I liked the Rex Williams signature on it.&lt;/p&gt;
&lt;p&gt;I saved £40 to buy it. It’s a cheap bit of wood and it’s been the butt of other players’ jokes for ages. Alex Higgins said it was ‘only good for holdin’ up f*g tomatoes!’&lt;/p&gt;
&lt;p&gt;But I insist on sticking with it. And I’ve won a lot of silverware, including seven World Championship trophies, with it. It’s a one-piece which I carry in a wooden, leather-bound case that’s much more expensive than the cue it houses.&lt;/p&gt;
&lt;p&gt;But in 2003, at Glasgow airport after a flight from Bangkok, it emerges through the rubber flaps on the carousel and even at twenty yards I can see that both case and cue are broken. Snapped almost clean in two, the whole thing now resembling some form of shepherd’s crook. The cue comes to where I’m standing, and I pick it up, the broken end dangling down forlornly.&lt;/p&gt;
&lt;p&gt;I could weep. Instead, I laugh.&lt;/p&gt;
&lt;p&gt;‘Well,’ I say to my stunned-looking friend John, ‘that’s my career over.’
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Stephen Hendry, &lt;a href=&quot;https://www.mirror.co.uk/sport/other-sports/snooker/stephen-hendry-reveals-pre-match-13186275&quot;&gt;The Mirror&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Small-improvements-leads-to-large-long-term-gains&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Small-improvements-leads-to-large-long-term-gains&quot; class=&quot;heading-ref&quot;&gt;Small improvements leads to large long-term gains&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Kaizen isn’t about massive overhauls or overnight success. Instead, it focuses on small, continuous improvements that add up to significant long-term gains.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://www.learnleansigma.com/continuous-improvement/kaizen-small-changes-big-results/&quot;&gt;What is Kaizen? A Guide to Continuous Improvement&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;I firmly believe that even small improvements are worth it as they add up over time (also see &lt;a href=&quot;https://www.investopedia.com/terms/c/compoundinterest.asp&quot;&gt;compound interest&lt;/a&gt; and how it relates to financial investments).&lt;/p&gt;
&lt;p&gt;An editor is a great example where even small improvements may have a big effect for the simple reason that you spend &lt;em&gt;so&lt;/em&gt; much time in your editor.
I’ve spent &lt;em&gt;hours&lt;/em&gt; almost every day inside (neo)vim since I started using it 15+ years ago.&lt;/p&gt;
&lt;p&gt;Even simple things like quickly changing text inside brackets (&lt;code&gt;ci[&lt;/code&gt;) instead of selecting text with your mouse might save hundreds of hours during a programming career—and that’s just one example.&lt;/p&gt;
&lt;p&gt;Naturally, as a developer you can find small but worthwhile improvements in other areas too, for instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Learning the programming languages and libraries you use a little better&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Customizing &lt;a href=&quot;/blog/2024/11/26/building_my_ultimate_keyboard/&quot;&gt;your keyboard&lt;/a&gt; and &lt;a href=&quot;/series/t-34/&quot;&gt;keyboard layout&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is more for comfort and health than speed but that makes it even more important, not less.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Increasing your typing speed&lt;/p&gt;
&lt;p&gt;Some people dismiss typing speed as they say they’re limited by their thinking, not typing.
But the benefit of typing faster (and more fluidly) isn’t really the overall time spent typing vs thinking;
it’s so you can continue thinking with as little interruption as possible.&lt;/p&gt;
&lt;p&gt;On some level you want to reduce the time typing in this chain:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;think… edit, think… edit, think…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s also why the Vim way of editing is so good—it’s based on making small edits and to return quickly to normal (thinking) mode.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some people ask how can you afford to spend time practicing Vim commands or to configure your editor as it takes away time from work?&lt;/p&gt;
&lt;p&gt;But I ask you: with a programming career of several decades and tens of thousands of hours to spend in front of your computer, how can you afford &lt;strong&gt;not&lt;/strong&gt; to?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Neovim-is-versatile&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Neovim-is-versatile&quot; class=&quot;heading-ref&quot;&gt;Neovim is versatile&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During the years I’ve done different things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Studied at the University and then started working as a developer.
&lt;/li&gt;
&lt;li&gt;
Used many different programming languages and paradigms.
&lt;/li&gt;
&lt;li&gt;
Changed domains many times (games, grammars &amp;amp; language design, graphics programming, web development, …)
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;/blog/2024/11/26/building_my_ultimate_keyboard/&quot;&gt;Switched keyboard&lt;/a&gt; and &lt;a href=&quot;/series/t-34/&quot;&gt;keyboard layout&lt;/a&gt; &lt;a href=&quot;/blog/2024/11/26/the_current_cybershard_layout/&quot;&gt;multiple times&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Been blogging and &lt;a href=&quot;/series/making-cryptobook/&quot;&gt;wrote a book&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The one constant through all of this has been Neovim.
Neovim may not have the best language specific integrations but it does everything well and the benefit of having the same setup for everything you do is not to be underestimated.
It pairs nicely with the idea of adding up small improvements over time; every small improvement that I add to my Neovim workflow will stay with me no matter what I work with.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I did use Emacs at work for years because their proprietary language only had an Emacs integration and I didn’t have the time nor energy to create one for Neovim.
While &lt;a href=&quot;https://github.com/emacs-evil/evil&quot;&gt;Evil&lt;/a&gt; made the experience survivable I realized then that I absolutely hate having my work setup be different from my setup at home.&lt;/p&gt;
&lt;p&gt;People weren’t overjoyed with being unable to choose their own editor and I’ve heard rumors that there’s now an extension for Visual Studio.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Neovim-is-easily-extensible&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Neovim-is-easily-extensible&quot; class=&quot;heading-ref&quot;&gt;Neovim is easily extensible&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Neovim: a Personalized Development Environment&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;TJ DeVries &lt;a href=&quot;https://www.youtube.com/watch?v=QMVIJhC9Veg&quot;&gt;A different take on editing code&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’ve always felt that Vimscript is the worst part of Vim.
Maybe that’s a weird statement as the scriptability of Vim is one if it’s strengths;
and to be fair, simple things are very nice:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;vimscript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight vim&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function viml&quot;&gt;nnoremap&lt;/span&gt; j gj
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function viml&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;support function viml&quot;&gt;expandtab&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But writing complex things in Vimscript is simply not a great experience.&lt;/p&gt;
&lt;p&gt;One of the major benefits of Neovim is the addition of Lua as a first-class scripting language.
Yes, Lua isn’t perfect and it’s often too verbose but it’s &lt;em&gt;so&lt;/em&gt; much better than Vimscript.
Lua is the main reason that the Neovim plugin ecosystem is currently a lot more vibrant than in Vim.&lt;/p&gt;
&lt;p&gt;Making it easier to write plugins is of course a boon, but the real benefit is in how it makes it even easier to make more complex customization for yourself.
Just plop down some Lua in the configuration files you already have and you’re done.
(Emacs worked this out to an even greater extent decades ago.)&lt;/p&gt;
&lt;p&gt;One way I use this customizability is to &lt;a href=&quot;/series/extending_neovim_for_my_blog/&quot;&gt;help me when I’m blogging&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
A custom picker to search and display blog posts
&lt;/li&gt;
&lt;li&gt;
Autocomplete tags, post urls, and more
&lt;/li&gt;
&lt;li&gt;
LSP-like functionality to display warnings and jump between posts
&lt;/li&gt;
&lt;li&gt;
Use treesitter to convert links, autoformat lists, and jump around
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Maybe you don’t need to create something this big but even small things such as disabling autoformat for certain file types in specific folders can be incredibly useful.&lt;/p&gt;
&lt;p&gt;Approachability should not be underestimated.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;While plugins in Lua is understandably the focus today, Neovim can still use plugins written in Vimscript and 99% of your old Vim configuration will still work in Neovim.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Neovim-wont-go-anywhere&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Neovim-wont-go-anywhere&quot; class=&quot;heading-ref&quot;&gt;Neovim won’t go anywhere&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The old is expected to stay longer than the young in proportion to their age.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Nassim Nicholas Taleb, “Antifragile”
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;The last big benefit with Neovim I’ll highlight—and why I feel fine with investing even more time into Neovim—is that Neovim will most likely continue to exist and thrive for years if not decades to come.&lt;/p&gt;
&lt;p&gt;While Vim has—after an impressive 30 years of development—recently &lt;a href=&quot;https://thenewstack.io/vim-after-bram-a-core-maintainer-on-how-theyve-kept-it-going/&quot;&gt;entered maintenance mode&lt;/a&gt;, activity in Neovim has steadily increased since the fork from Vim more than a decade ago.
The amount of &lt;a href=&quot;https://neovimcraft.com/&quot;&gt;high quality plugins&lt;/a&gt;, interest in &lt;a href=&quot;https://trends.google.com/trends/explore?date=today%205-y&amp;amp;q=neovim&quot;&gt;Google trends&lt;/a&gt;, and &lt;a href=&quot;https://star-history.com/#neovim/neovim&amp;amp;Date&quot;&gt;GitHub activity&lt;/a&gt; have all been trending upwards.
Neovim was also the most desired editor according to the &lt;a href=&quot;https://survey.stackoverflow.co/2024/technology#2-integrated-development-environment&quot;&gt;latest Stackoverflow developer survey&lt;/a&gt; and the overall buzz and excitement in the community is at an all-time high.&lt;/p&gt;
&lt;p&gt;With the self-reinforced behavior and benefits of investing into a versatile and flexible editor with a huge plugin ecosystem such as Neovim I see no reason for the trend to taper off anytime soon.&lt;/p&gt;
&lt;p&gt;Neovim will probably never be as popular as something like VSCode but as an open source project backed by excited developers, Neovim will probably be around long after VSCode has been discontinued for The Next Big Thing.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Securing my partner&apos;s digital life</title><id>http://jonashietala.se/blog/2025/01/20/securing_my_partners_digital_life/index.html</id><updated>2025-01-20T12:58:29+00:00</updated><link href="https://www.jonashietala.se/blog/2025/01/20/securing_my_partners_digital_life" rel="alternate"/><published>2025-01-20T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been with Veronica for over a decade now and I think I’m starting to know her fairly well.
Yet she still manages to surprise me.
For instance, a couple of weeks ago she came and asked me about email security:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I worry that my email password is too weak.
Can you help me change email address and make it secure?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It was completely unexpected—but I’m all for it.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/it_superhero.jpg&quot;&gt;
&lt;/figure&gt;
&lt;section id=&quot;The-action-plan&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-action-plan&quot; class=&quot;heading-ref&quot;&gt;The action plan&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All heroic journeys needs a plan; here’s mine:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Buy her a domain name (her &lt;code&gt;.com&lt;/code&gt; surname was available).
&lt;/li&gt;
&lt;li&gt;
Migrate her email to &lt;a href=&quot;https://www.fastmail.com/&quot;&gt;Fastmail&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Setup &lt;a href=&quot;https://bitwarden.com/&quot;&gt;Bitwarden&lt;/a&gt; as a password manager.
&lt;/li&gt;
&lt;li&gt;
Use a &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; to secure the important services.
&lt;/li&gt;
&lt;/ol&gt;
&lt;section id=&quot;Why-a-domain&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-a-domain&quot; class=&quot;heading-ref&quot;&gt;Why a domain?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you ever want (or need) to change email providers it’s very nice to have your own domain.
For instance, Veronica has a &lt;code&gt;hotmail.com&lt;/code&gt; address but she can’t bring that with her if she moves to &lt;a href=&quot;https://www.fastmail.com/&quot;&gt;Fastmail&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Worse, what if she gets locked out of her Outlook account for some reason?
It might happen if you forget your password, someone breaks into your account, or even by accident.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;For example, &lt;a href=&quot;https://9to5mac.com/2024/04/26/signed-out-of-apple-id-account-problem-password/&quot;&gt;Apple users recently got locked out of their Apple IDs&lt;/a&gt; without any apparent reason and Gmail &lt;a href=&quot;https://news.ycombinator.com/item?id=32862713&quot;&gt;has&lt;/a&gt; been &lt;a href=&quot;https://mailchi.mp/shwood/bamboozlers-514882?e=4be3990d97&quot;&gt;notorious&lt;/a&gt; about &lt;a href=&quot;https://news.ycombinator.com/item?id=34116361&quot;&gt;locking out&lt;/a&gt; users &lt;a href=&quot;https://news.ycombinator.com/item?id=25176151&quot;&gt;for no reason&lt;/a&gt;.
Some providers may be better but this is a systemic problem that can happen at any service.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;In almost all cases, your email is your key to the rest of your digital life.
The email address is your username and to reset your password you use your email.
&lt;mark&gt;If you lose access to your email you lose everything&lt;/mark&gt;.&lt;/p&gt;
&lt;p&gt;When you control your domain, you can point the domain to a new email provider and continue with your life.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-pay-for-email&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-pay-for-email&quot; class=&quot;heading-ref&quot;&gt;Why pay for email?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the first things Veronica told me when I proposed that she’d change providers was that she didn’t want to pay.
It’s a common sentiment online that email must be cheap (or even free).&lt;/p&gt;
&lt;p&gt;I don’t think that email is the area where cost should be the most significant factor.
As I argued for in &lt;a href=&quot;#Why-a-domain&quot;&gt;why you should own your email’s domain&lt;/a&gt;, your email is your most important digital asset.
If email is so important, why try to be cheap about it?
You should spend your money on the important things and shouldn’t spend money on the unimportant things.&lt;/p&gt;
&lt;p&gt;Paying for email gives you a couple of nice things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Human support.&lt;/p&gt;
&lt;p&gt;It’s all too easy to get shafted by algorithms where you might get banned because you triggered some edge case (such as resetting your password outside your usual IP address).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ability to use your own domain.&lt;/p&gt;
&lt;p&gt;Having a custom domain is a paid feature at most email providers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A long-term viable business.&lt;/p&gt;
&lt;p&gt;How do you run an email company if you don’t charge for it?&lt;br&gt;
&lt;em&gt;(You sell out your users or you close your business.)&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-a-password-manager&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-a-password-manager&quot; class=&quot;heading-ref&quot;&gt;Why a password manager?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best thing you can do security wise is to adopt a password manager.
Then you don’t have to try to remember dozens of passwords (leading to easy-to-remember and duplicate passwords) and can focus on remembering a single (stronger) password, confident that the password manager will remember all the rest.&lt;/p&gt;
&lt;p&gt;“Putting all your passwords in one basket” is a concern of course but I think the pros outweigh the cons.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-a-YubiKey&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-a-YubiKey&quot; class=&quot;heading-ref&quot;&gt;Why a &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt;?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To take digital security to the next level you should use &lt;a href=&quot;https://www.microsoft.com/en-us/security/business/security-101/what-is-two-factor-authentication-2fa&quot;&gt;two-factor authentication (2FA)&lt;/a&gt;.
2FA is an extra “thing” in addition to your password you need to be able to login.
It could be a code sent to your phone over SMS (insecure), to your email (slightly better), a code from a 2FA app on your phone such as &lt;a href=&quot;https://github.com/beemdevelopment/Aegis&quot;&gt;Aegis Authenticator&lt;/a&gt; (good), or from a hardware token (most secure).&lt;/p&gt;
&lt;p&gt;It’s easy to think that I went with a &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; because it’s the most secure option; but the biggest reason is that a &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; is  more convenient than a 2FA app.&lt;/p&gt;
&lt;p&gt;With a 2FA app you have to whip out your phone, open the 2FA app, locate the correct site, and then copy the TOTP code into the website (quickly, before the code changes).
It’s honestly not that convenient, even for someone like me who’s used this setup for years.&lt;/p&gt;
&lt;p&gt;With a &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; you plug it into a USB port and press it when it flashes.
Or on the phone you can use NFC.
NFC is slightly more annoying compared to plugging it in as you need to move/hold it in a specific spot, yet it’s still preferable to having to jump between apps on the phone.&lt;/p&gt;
&lt;p&gt;There are hardware keys other than &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; of course.
I’ve used &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; for years and have a good experience.
Don’t fix what isn’t broken.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;The-setup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-setup&quot; class=&quot;heading-ref&quot;&gt;The setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s a few quick notes on how I setup her new accounts:&lt;/p&gt;
&lt;section id=&quot;Password-management-with-Bitwarden&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Password-management-with-Bitwarden&quot; class=&quot;heading-ref&quot;&gt;Password management with Bitwarden&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first thing we did was setup &lt;a href=&quot;https://bitwarden.com/&quot;&gt;Bitwarden&lt;/a&gt; as the password manager for her.
I chose the family plan so I can handle the billing.&lt;/p&gt;
&lt;p&gt;To give her access I installed &lt;a href=&quot;https://bitwarden.com/&quot;&gt;Bitwarden&lt;/a&gt; as:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
An app on her phone
&lt;/li&gt;
&lt;li&gt;
A browser plugin on her computer
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I gave her a &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; and registered it with &lt;a href=&quot;https://bitwarden.com/&quot;&gt;Bitwarden&lt;/a&gt; for additional security.
As a backup I also registered my own &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt;s on her account; if she loses her key we still have others she can use.&lt;/p&gt;
&lt;p&gt;Although it was a bit confusing for her I think she appreciates not having to remember a dozen different passwords and can simply remember one (stronger) password.
We can also share passwords easily via &lt;a href=&quot;https://bitwarden.com/&quot;&gt;Bitwarden&lt;/a&gt; (for news papers, Spotify, etc).&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt; itself is very user friendly and she hasn’t run into any usability issues.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Email-on-Fastmail&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Email-on-Fastmail&quot; class=&quot;heading-ref&quot;&gt;Email on Fastmail&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the core security up and running the next step was to change her email:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Gave her an email address on &lt;a href=&quot;https://www.fastmail.com/&quot;&gt;Fastmail&lt;/a&gt; with her own domain (&lt;code&gt;&amp;lt;firstname&amp;gt;@&amp;lt;lastname&amp;gt;.com&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;She has a basic account that I manage (there’s a &lt;a href=&quot;https://www.fastmail.help/hc/en-us/articles/8033939068815-2024-pricing-and-plan-updates&quot;&gt;Duo plan&lt;/a&gt; that I couldn’t migrate to at this time).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I secured the account with our &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt;s and a generated password stored in &lt;a href=&quot;https://bitwarden.com/&quot;&gt;Bitwarden&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We bolstered the security of her old Hotmail account by generating a new password and registering our &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt;s.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Forward all email from her old Hotmail address to her new address.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With this done she has a secure email account with an email address that she owns.&lt;/p&gt;
&lt;p&gt;As is proper she’s been changing her contact information and changing email address in her other services.
It’s a slow process but I can’t be too critical—I still have a few services that use my old Gmail address even though I migrated to my own domain more than a decade ago.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Notes-on-recovery-and-redundancy&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Notes-on-recovery-and-redundancy&quot; class=&quot;heading-ref&quot;&gt;Notes on recovery and redundancy&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It’s great to worry about weak phishing, weak passwords, and getting hacked.
But for most people the much bigger risk is to forget your password or lose your second factor auth, and get locked out that way.&lt;/p&gt;
&lt;p&gt;To reduce the risk of losing access to her accounts we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Multiple &lt;a href=&quot;https://www.yubico.com/products/yubikey-5-overview/&quot;&gt;YubiKey&lt;/a&gt;s for all accounts.
&lt;/li&gt;
&lt;li&gt;
The recovery codes for all accounts are written down and secured.
&lt;/li&gt;
&lt;li&gt;
My own accounts can recover her &lt;a href=&quot;https://bitwarden.com/&quot;&gt;Bitwarden&lt;/a&gt; and &lt;a href=&quot;https://www.fastmail.com/&quot;&gt;Fastmail&lt;/a&gt; accounts via their built-in recovery functionality.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Perfect-is-the-enemy-of-good&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Perfect-is-the-enemy-of-good&quot; class=&quot;heading-ref&quot;&gt;Perfect is the enemy of good&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some go further than we’ve done here, others do less, and I think that’s fine.
It’s important to not compare yourself with others too much;
even small security measures makes a big difference in practice.&lt;/p&gt;
&lt;p&gt;Not doing anything at all because you feel overwhelmed is worse than doing something, even something simple as making sure you’re using a strong password for your email account.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>First impressions of Ghostty</title><id>http://jonashietala.se/blog/2025/01/06/first_impressions_of_ghostty/index.html</id><updated>2025-01-19T07:16:57+00:00</updated><link href="https://www.jonashietala.se/blog/2025/01/06/first_impressions_of_ghostty" rel="alternate"/><published>2025-01-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;There are two conflicting forces in play in setting up your computer environment:&lt;/p&gt;
&lt;ol type=&quot;i&quot;&gt;
&lt;li&gt;
It’s worthwhile to pursue small improvements in frequently used tools.
&lt;/li&gt;
&lt;li&gt;
It’s not productive to get stuck tweaking your setup endlessly.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s common to find people get stuck at the extreme ends of the spectrum;
some programmers refuse to configure or learn their tools at all, while others get stuck re-configuring their setups constantly without any productivity gains to show for it.&lt;/p&gt;
&lt;p&gt;Finding a balance can be tricky.
With regards to terminals I’ve been using &lt;a href=&quot;https://github.com/alacritty/alacritty&quot;&gt;alacritty&lt;/a&gt; for many years.
It gets the job done but I don’t know if I’m missing out on anything?
I’ve been meaning to look at alternatives like &lt;a href=&quot;https://github.com/wez/wezterm&quot;&gt;wezterm&lt;/a&gt; and &lt;a href=&quot;https://github.com/kovidgoyal/kitty&quot;&gt;kitty&lt;/a&gt; but I never got far enough to try them out.&lt;/p&gt;
&lt;p&gt;On one hand it’s just a terminal, what difference could it make?&lt;br&gt;
On the other hand, I spend countless of hours every day inside a terminal so even a small improvement should pay off in the long run.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt;, a terminal so hyped up it made me drop any useful things I was working on and see what the fuzz was about.
I don’t quite get why people hype up a terminal of all things but here we are.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; didn’t revolutionize my setup or anything but I admit that &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; is quite nice and it has replaced &lt;a href=&quot;https://github.com/alacritty/alacritty&quot;&gt;alacritty&lt;/a&gt; as my terminal.&lt;/p&gt;
&lt;section id=&quot;I-just-want-a-blank-canvas-without-any-decorations&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#I-just-want-a-blank-canvas-without-any-decorations&quot; class=&quot;heading-ref&quot;&gt;I just want a blank canvas without any decorations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the big selling points of &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; is its &lt;a href=&quot;https://gpanders.com/blog/ghostty-is-native-so-what/&quot;&gt;native platform integration&lt;/a&gt;.
It’s supposed to integrate well with your window manager so it looks the same and gives you some extra functionality…
But I don’t know why I should care—I just want a big square without decorations of any kind.&lt;/p&gt;
&lt;p&gt;You’re supposed to to be able to simply turn off any window decorations:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;ghostty&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;window-decoration&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At the moment &lt;a href=&quot;https://github.com/ghostty-org/ghostty/issues/2023&quot;&gt;there’s a bug&lt;/a&gt; that requires you set some weird GTK settings to fully remove the borders:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;ghostty&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;gtk-titlebar&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;gtk-adwaita&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s unfortunate as I haven’t done any GKT configuration on my machine (I use &lt;a href=&quot;https://xmonad.org/&quot;&gt;XMonad&lt;/a&gt; as my window manager and I don’t have any window decorations anywhere).&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;There might some useful native features I don’t know about.
The password input style is neat for instance, although I’m not sure it does anything functionally different compared to other terminals:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/ghostty_password.png&quot;&gt;
&lt;/figure&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Cursor-invert&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Cursor-invert&quot; class=&quot;heading-ref&quot;&gt;Cursor invert&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;ghostty&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;cursor-invert-fg-bg&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/alacritty/alacritty&quot;&gt;alacritty&lt;/a&gt; I’ve had the cursor invert the background and foreground and you can do that in &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;I ran into an issue where it interferes with &lt;a href=&quot;https://github.com/lukas-reineke/indent-blankline.nvim&quot;&gt;indent-blankline.nvim&lt;/a&gt; making the cursor very hard to spot in indents (taking the color of the indent guides, which is by design low contrast with the background).&lt;/p&gt;
&lt;p&gt;Annoying but it gave me the shove I needed to try out different plugins to see if the problem persisted.
I ended up with (an even nicer) setup using &lt;a href=&quot;https://github.com/folke/snacks.nvim/tree/main&quot;&gt;snacks.nvim&lt;/a&gt; that doesn’t hide the cursor:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/ghostty_indent_differences.png&quot;&gt;
&lt;figcaption&gt;Left: &lt;a href=&quot;https://github.com/lukas-reineke/indent-blankline.nvim&quot;&gt;indent-blankline.nvim&lt;/a&gt; (cursor barely visible)&lt;br&gt;
Right: &lt;a href=&quot;https://github.com/folke/snacks.nvim/tree/main&quot;&gt;snacks.nvim&lt;/a&gt; (cursor visible and it highlights scope).

&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Minimum-contrast&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Minimum-contrast&quot; class=&quot;heading-ref&quot;&gt;Minimum contrast&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unreadable &lt;code&gt;ls&lt;/code&gt; output is a staple of the excellent Linux UX.
It might look like this:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/ls_unreadable.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Super annoying.&lt;/p&gt;
&lt;p&gt;You can of course configure the &lt;code&gt;ls&lt;/code&gt; output colors but that’s just for one program and it won’t automatically follow when you &lt;code&gt;ssh&lt;/code&gt; to another server.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt;’s &lt;code&gt;minimum-contrast&lt;/code&gt; option ensures that the text and background always has enough contrast to be visible:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;ghostty&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;minimum-contrast&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;1.05&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/ls_readable.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Most excellent.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;This feature has the potential to break “eye candy” features, such the Neovim indent lines plugins if you use a low contrast configuration.
I still run into minor issues from time to time.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Hide-cursor-while-typing&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Hide-cursor-while-typing&quot; class=&quot;heading-ref&quot;&gt;Hide cursor while typing&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;ghostty&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;mouse-hide-while-typing&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A small quality-of-life feature is the ability to hide the cursor when typing.
I didn’t know I needed this in my life.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Consistent-font-sizing-between-desktop-and-laptop&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Consistent-font-sizing-between-desktop-and-laptop&quot; class=&quot;heading-ref&quot;&gt;Consistent font sizing between desktop and laptop&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/alacritty/alacritty&quot;&gt;alacritty&lt;/a&gt; I have an annoying problem where I need to use a very different font size on my laptop and my desktop (&lt;code&gt;8&lt;/code&gt; and &lt;code&gt;12&lt;/code&gt;).
This wasn’t always the case and I think something may have changed in &lt;a href=&quot;https://github.com/alacritty/alacritty&quot;&gt;alacritty&lt;/a&gt; but I’m not sure.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; doesn’t have this problem and I can now use the same font settings across my machines (
&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;font-size&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;16&lt;/span&gt;
&lt;/code&gt;).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Ligature-support&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Ligature-support&quot; class=&quot;heading-ref&quot;&gt;Ligature support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/alacritty/alacritty/issues/50&quot;&gt;issue for adding ligatures to alacritty&lt;/a&gt; was closed eight years ago
and even though I wanted to try ligatures I couldn’t be bothered to “run a low quality fork”.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; seems like the opposite of “low quality” and it renders &lt;a href=&quot;https://github.com/be5invis/Iosevka&quot;&gt;Iosevka&lt;/a&gt;’s ligatures very well:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/iosevka_ligatures.png&quot;&gt;
&lt;figcaption&gt;My configured ligatures of Iosevka, rendered in Ghostty.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Overall I feel that the font rendering in &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; is a little better than in &lt;a href=&quot;https://github.com/alacritty/alacritty&quot;&gt;alacritty&lt;/a&gt;, although that might be recency bias.
I’m still undecided on ligatures but I love that I don’t have to feel limited by the terminal.&lt;/p&gt;
&lt;p&gt;I use a &lt;a href=&quot;/iosevka&quot;&gt;custom Iosevka build&lt;/a&gt; with these &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; settings:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;ghostty&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;font-family&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;IosevkaTreeLig Nerd Font&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;font-style&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Medium&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;font-style-bold&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Bold&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;font-style-italic&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Medium Italic&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;font-style-bold-italic&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Bold Italic&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;font-size&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;16&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Colorscheme&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Colorscheme&quot; class=&quot;heading-ref&quot;&gt;Colorscheme&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; has an absolutely excellent theme selector with a bunch of included themes (&lt;code&gt;ghostty +list-themes&lt;/code&gt;) &lt;a href=&quot;https://github.com/savq/melange-nvim&quot;&gt;melange-nvim&lt;/a&gt; wasn’t included, so I had to configure the colorscheme myself.
It was fairly straightforward even though the &lt;code&gt;palette = 0=&lt;/code&gt; syntax was a bit surprising:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;ghostty&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight ghostty&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# The dark variant of melange&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;background&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;#292522&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;foreground&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;#ECE1D7&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;0=#867462&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;1=#D47766&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;2=#85B695&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;3=#EBC06D&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;4=#A3A9CE&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;5=#CF9BC2&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;6=#89B3B6&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;7=#ECE1D7&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;8=#34302C&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;9=#BD8183&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;10=#78997A&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;11=#E49B5D&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;12=#7F91B2&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;13=#B380B0&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;14=#7B9695&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;palette&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;15=#C1A78E&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# I think it&amp;#39;s nice to colorize the selection too&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;selection-background&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;#403a36&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;selection-foreground&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;#c1a78e&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Im-happy-with-Ghostty&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Im-happy-with-Ghostty&quot; class=&quot;heading-ref&quot;&gt;I’m happy with Ghostty&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the end &lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;Ghostty&lt;/a&gt; has improved my setup and I’m happy I took time to try it out.
It took a little more time than “just launch it” but it absolutely wasn’t a big deal.
The reward was a few pleasant improvements that have improved my life a little.&lt;/p&gt;
&lt;p&gt;And perhaps most important of all: I’m now an alpha Nerd that uses a terminal written in Zig.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;Did I create a custom highlighter for the Ghostty configuration file just to have proper syntax highlighting for this one blog post?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/treeman/tree-sitter-ghostty&quot;&gt;You bet I did&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(It’s a simple &lt;a href=&quot;/blog/2024/03/19/lets_create_a_tree-sitter_grammar&quot;&gt;treesitter grammar&lt;/a&gt;.)&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
</content></entry><entry><title>2024 in review</title><id>http://jonashietala.se/blog/2025/01/05/2024_in_review/index.html</id><updated>2025-01-19T07:16:57+00:00</updated><link href="https://www.jonashietala.se/blog/2025/01/05/2024_in_review" rel="alternate"/><published>2025-01-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s time for my &lt;a href=&quot;/blog/tags/yearly_review&quot;&gt;15th yearly review&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;Nerdy-things-I-enjoyed&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Nerdy-things-I-enjoyed&quot; class=&quot;heading-ref&quot;&gt;Nerdy things I enjoyed&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I read a lot of fantasy books this year!&lt;/p&gt;
&lt;p&gt;My favorite new series were &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Kingkiller_Chronicle&quot;&gt;The Kingkiller Chronicle&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Scott_Lynch#Gentleman_Bastard_Sequence&quot;&gt;Gentlemen Bastards series&lt;/a&gt;, and &lt;a href=&quot;https://www.brandonsanderson.com/pages/the-stormlight-archive-series&quot;&gt;The Stormlight Archive&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;If you’re curious about Sanderson’s books but a little apprehensive about jumping into a massive series such as &lt;a href=&quot;https://www.brandonsanderson.com/pages/the-stormlight-archive-series&quot;&gt;The Stormlight Archive&lt;/a&gt; then I’ll recommend &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Emperor%27s_Soul&quot;&gt;The Emperor’s Soul&lt;/a&gt; as an excellent little introduction.
The standalone book &lt;a href=&quot;https://www.brandonsanderson.com/blogs/blog/warbreaker-rights-and-downloads&quot;&gt;Warbreaker&lt;/a&gt; is also fantastic (available &lt;a href=&quot;https://www.brandonsanderson.com/blogs/blog/warbreaker-rights-and-downloads&quot;&gt;for free on Brandon’s website&lt;/a&gt;).&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Customizing Neovim was fun and rewarding.&lt;/p&gt;
&lt;p&gt;It’s amazing I got anything productive done this year…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I really enjoy working with Rust in my own hobby projects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://elixir-lang.org/blog/2024/12/19/elixir-v1-18-0-released/&quot;&gt;Types are coming to Elixir&lt;/a&gt; and I’m loving it.&lt;/p&gt;
&lt;p&gt;(I recently migrated some small projects to v1.18 and found a bunch of errors.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam programming language&lt;/a&gt; shows a lot of promise.&lt;/p&gt;
&lt;p&gt;My one gripe is the pain of manually encoding/decoding JSON (even with the various libraries).
Compared to for example Elixir dynamic encoding or Rust’s 
&lt;code class=&quot;highlight rust&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;Deserialize&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; it just feels so bad that I’ve avoided Gleam for some projects.
Shame on me?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CSS is alive and better than ever.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Things-I-accomplished&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Things-I-accomplished&quot; class=&quot;heading-ref&quot;&gt;Things I accomplished&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I quit my job and started my own company.&lt;/p&gt;
&lt;p&gt;At the moment I’m focusing on consulting but maybe something else can grow from it one day?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I &lt;a href=&quot;/blog/2024/&quot;&gt;wrote 26 blog posts&lt;/a&gt;—it was quite a productive blogging year for me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I built a &lt;a href=&quot;/blog/2024/11/26/building_my_ultimate_keyboard&quot;&gt;custom keyboard&lt;/a&gt; together with a &lt;a href=&quot;/blog/2024/11/26/the_current_cybershard_layout&quot;&gt;custom keyboard layout&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Made the eBook for &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;Why Cryptocurrencies?&lt;/a&gt; freely available and finally finished the &lt;a href=&quot;/series/making-cryptobook/&quot;&gt;How I wrote ‘Why Cryptocurrencies?’&lt;/a&gt; series.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I wrote a &lt;a href=&quot;/blog/2024/03/19/lets_create_a_tree-sitter_grammar&quot;&gt;Tree-sitter grammar for Djot&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;I need to be more active maintaining it…
But it’s hard to get motivated as I’ve got so many other interesting things I’d like to work on.
Managing an open source project is not for the faint of heart (or the easily distracted).&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finished the blog series about &lt;a href=&quot;/series/voron_trident&quot;&gt;building my first 3D printer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m up to over 2100 printing hours with the machine so it’s safe to say I’ve been using it, not &lt;em&gt;only&lt;/em&gt; playing around with.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2024/10/08/writing_home_assistant_automations_using_genservers_in_elixir&quot;&gt;Rewrote my lighting home automation&lt;/a&gt; from Python to Elixir.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I realized that &lt;a href=&quot;/blog/2024/09/25/why_i_still_blog_after_15_years&quot;&gt;meta-blogging&lt;/a&gt; is a great way to get &lt;a href=&quot;https://news.ycombinator.com/item?id=41646531&quot;&gt;virtual points on Hacker News&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Tentative-plansgoalswishes-for-2025&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Tentative-plansgoalswishes-for-2025&quot; class=&quot;heading-ref&quot;&gt;Tentative plans/goals/wishes for 2025&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For some reason the idea of writing a fantasy novel got stuck in my head.&lt;/p&gt;
&lt;p&gt;I had a stint where I listened to dozens of hours of advice for aspiring writers and started planning a series.
The excitement tapered off a bit during the Christmas holidays and I don’t know if this was just a temporary sidetrack or if it’s something I’ll actually end up doing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Design a one-handed keyboard layout.&lt;/p&gt;
&lt;p&gt;Again, this was just something my brain got stuck thinking about and I’m not sure if it’s just a fleeting idea or something I &lt;em&gt;need&lt;/em&gt; to do so I can stop thinking about it.
(Sometimes just a little planning plus solving the most difficult problems are enough—I don’t have to finish all the crazy/dumb ideas I get for my mind to consider them “done”.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complete my second 3D printer.&lt;/p&gt;
&lt;p&gt;There’s no point in having a single printer; what if I break it and I can no longer print replacement parts for it?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Develop my home automation system more.&lt;/p&gt;
&lt;p&gt;I’ve got a &lt;em&gt;ton&lt;/em&gt; of things I’d like to improve (or play around with).
For instance, yesterday I received the &lt;a href=&quot;https://www.home-assistant.io/voice-pe/&quot;&gt;Home Assistant Voice Preview Edition&lt;/a&gt; that I hope works as well as advertised.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
</content></entry><entry><title>A type checking error in Elixir 1.18</title><id>http://jonashietala.se/blog/2024/12/30/type_checking_in_elixir_118/index.html</id><updated>2025-01-19T07:16:57+00:00</updated><link href="https://www.jonashietala.se/blog/2024/12/30/type_checking_in_elixir_118" rel="alternate"/><published>2024-12-30T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Although I’m a big Elixir fan, the lack of static typing has always been my biggest annoyance (and why I think &lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam&lt;/a&gt; is so cool).
I think static typing helps catch bugs earlier and in an automated way, leading to less buggy software and saves time in the long run.&lt;/p&gt;
&lt;p&gt;To my great joy Elixir is working on &lt;a href=&quot;https://elixir-lang.org/blog/2023/06/22/type-system-updates-research-dev/&quot;&gt;a new type system&lt;/a&gt; that will hopefully give us the early type checking errors I’ve been craving for.
The system has been rolled out in steps &lt;a href=&quot;https://elixir-lang.org/blog/2024/06/12/elixir-v1-17-0-released/&quot;&gt;since v1.17&lt;/a&gt; and when I migrated to &lt;a href=&quot;https://elixir-lang.org/blog/2024/12/19/elixir-v1-18-0-released/&quot;&gt;v1.18&lt;/a&gt; I found my first type checking warning that I wanted to highlight.&lt;/p&gt;
&lt;section id=&quot;Comparison-with-structs&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Comparison-with-structs&quot; class=&quot;heading-ref&quot;&gt;Comparison with structs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the offending code with the corresponding warning:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;get_surrounding_events_as_dt&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;events&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; now &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; %&lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  time &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;to_time&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;now&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  next_i &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;find_index&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;events&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;_&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; event_time&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt; time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;&amp;lt;&lt;/span&gt; event_time &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator other elixir&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;warning: comparison with structs found:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    time &lt; event_time
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;given types:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    dynamic(%Time{}) &lt; dynamic()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;where &quot;event_time&quot; was given the type:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    # type: dynamic()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    # from: lib/haex/sun.ex
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    {_, event_time}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;where &quot;time&quot; was given the type:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    # type: dynamic(%Time{})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    # from: lib/haex/sun.ex:88:10
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    time = DateTime.to_time(now)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Comparison operators (&gt;, &lt;, &gt;=, &lt;=, min, and max) perform structural and not semantic comparison.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Comparing with a struct won&apos;t give meaningful results.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Structs that can be compared typically define a compare/2 function within their modules that
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;can be used for semantic comparison.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;typing violation found at:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│     next_i = Enum.find_index(events, fn {_, event_time} -&gt; time &lt; event_time end) || 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│                                                                 ~
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(The type checker cannot yet resolve &lt;code&gt;event_time&lt;/code&gt; to the
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Time&lt;/span&gt;&lt;/code&gt; struct, leaving it as &lt;code&gt;dynamic()&lt;/code&gt; in the text above.)&lt;/p&gt;
&lt;p&gt;The issue here as that &lt;code&gt;&amp;lt;&lt;/code&gt; isn’t overloaded for the 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Time&lt;/span&gt;&lt;/code&gt; struct (like it would be in for instance Rust) and will instead perform structural comparison.&lt;/p&gt;
&lt;p&gt;You should use 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;before?&lt;/code&gt; instead of &lt;code&gt;&amp;lt;&lt;/code&gt; (and 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;before&lt;/code&gt; for &lt;code&gt;DateTime&lt;/code&gt; etc).&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;As it happens for 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Time&lt;/span&gt;&lt;/code&gt; this doesn’t seem to be an issue as the structure &lt;em&gt;happens&lt;/em&gt; to perform the comparisons in the same order as 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;before?&lt;/code&gt;, which this test verifies:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;test &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;check_times&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  times &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;zip&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword operator range elixir&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword operator range elixir&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;59&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword operator range elixir&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;59&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;map&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;h&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; m&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;new!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;h&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; m&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;for&lt;/span&gt; a &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;&amp;lt;-&lt;/span&gt; times &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;for&lt;/span&gt; b &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;&amp;lt;-&lt;/span&gt; times &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      assert a &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;&amp;lt;&lt;/span&gt; b &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;before?&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is not the case for 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;DateTime&lt;/span&gt;&lt;/code&gt;, which did cause a production bug in my home automation system, that my spouse complained about…&lt;/p&gt;
&lt;p&gt;Remember this when you think about types: &lt;strong&gt;type checking saves relationships&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;My-hope-for-the-future&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#My-hope-for-the-future&quot; class=&quot;heading-ref&quot;&gt;My hope for the future&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve always disliked matching against atoms in Elixir as it’s so easy to make a mistake, for example like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Supervisor&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_child&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;supervisor&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; child_spec&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;error&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;already_stated&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; pid&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;info&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Got pid: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;inspect&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;pid&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(There’s a missing &lt;code&gt;r&lt;/code&gt; in 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;already_stated&lt;/span&gt;&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;At the moment this doesn’t produce an error but I really hope we’ll reach this point sooner rather than later as I make these kinds of mistakes all the time.
I think I catch most of these with tests but I’m sure some slip through.&lt;/p&gt;
&lt;p&gt;I hope this isn’t that far away as the v1.18 type checker manages to catch a simpler case like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;num_to_descr&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;num&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; num &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;one&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant numeric elixir&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;two&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    _ &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;many&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;num&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; num_to_descr&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;num&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;zero&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;puts&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;zero&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    x &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;puts&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Other: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;    warning: the following clause will never match:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        :zero
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    because it attempts to match on the result of:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        num_to_descr(num)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    which has type:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        dynamic(:many or :one or :two)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    typing violation found at:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    │
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 41 │       :zero -&gt; IO.puts(&quot;zero&quot;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    │       ~~~~~~~~~~~~~~~~~~~~~~~~
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
</content></entry><entry><title>Building my ultimate keyboard</title><id>http://jonashietala.se/blog/2024/11/26/building_my_ultimate_keyboard/index.html</id><updated>2026-04-27T10:06:42+00:00</updated><link href="https://www.jonashietala.se/blog/2024/11/26/building_my_ultimate_keyboard" rel="alternate"/><published>2024-11-26T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/cybershard.jpg&quot;&gt;
&lt;figcaption&gt;The Cybershard keyboard.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;What comes to mind when you see the description “the ultimate keyboard”?&lt;/p&gt;
&lt;p&gt;There are &lt;em&gt;many&lt;/em&gt; keyboards in this world; here are some that might fit the “ultimate” moniker:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.daskeyboard.com/daskeyboard-4-ultimate/&quot;&gt;Das Keyboard 4 Ultimate mechanical keyboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/DataHand&quot;&gt;DataHand&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://ergodox-ez.com/&quot;&gt;Ergodox EZ&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.moergo.com/&quot;&gt;Glove80&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://hhkeyboard.us/&quot;&gt;Happy Hacking Keyboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Model_M_keyboard&quot;&gt;Model M Keyboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Stenotype&quot;&gt;Stenotype&lt;/a&gt; keyboards.
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://ultimatehackingkeyboard.com/&quot;&gt;Ultimate Hacking Keyboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.charachorder.com/&quot;&gt;CharaChorder&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some even have “ultimate” in their name, although I’ll assert that they’re far from ultimate.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any man who must say, “I am the King”, is no true king.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Tywin Lannister
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’ll go one step further to say that no keyboard is universally the ultimate because it’s impossible to agree on how to rank different keyboards.
For example, while I personally prefer a split keyboard, you might not.
Some people have very long fingers and some have very short fingers, making some layouts more preferable.
Others may not even have 10 fingers (or both hands), requiring more drastic modifications.&lt;/p&gt;
&lt;p&gt;If an ultimate keyboard exists, it differs from person to person.
This is my attempt to build &lt;em&gt;my&lt;/em&gt; ultimate keyboard.&lt;/p&gt;
&lt;section id=&quot;My-wishlist&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#My-wishlist&quot; class=&quot;heading-ref&quot;&gt;My wishlist&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To me, the ultimate keyboard should have these features:&lt;/p&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
&lt;p&gt;Should be split to support a more natural typing position.&lt;/p&gt;
&lt;p&gt;Really the biggest ergonomical leap in my opinion.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Customized for my own fingers and typing eccentricities.&lt;/p&gt;
&lt;p&gt;Column stagger, curvatures and tenting are features I think I want but they need to be tuned, probably by trial-and-error.
The position of the thumb keys is another sticking point that the other keyboards I’ve tried have failed to get just right.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Have an integrated trackball or trackpad.&lt;/p&gt;
&lt;p&gt;This way I don’t have to move my hand so far and I can free up some valuable desk space.
It shouldn’t be operated with my thumb due to my RSI.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Contain the keys I need but no more.&lt;/p&gt;
&lt;p&gt;I like smaller keyboards and I’ve been very happy and with &lt;a href=&quot;/series/t-34&quot;&gt;my custom keyboard layout&lt;/a&gt; that only has 34 keys.
Some modifications are fine of course but for the most part I want to be able to use the same layout on both the &lt;a href=&quot;https://github.com/pierrechevalier83/ferris&quot;&gt;Ferris&lt;/a&gt; and my new keyboard.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;2&quot; type=&quot;i&quot;&gt;
&lt;li&gt;
To fulfill these requirements I need to be able to customize all parts of the keyboard and I really don’t want to learn CAD and create one from scratch; I wonder what alternatives I have?
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Cosmos-keyboard-configurator&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Cosmos-keyboard-configurator&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://ryanis.cool/cosmos/&quot;&gt;Cosmos&lt;/a&gt; keyboard configurator&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Having looked around, I probably want something similar to a &lt;a href=&quot;https://github.com/adereth/dactyl-keyboard&quot;&gt;Dactyl&lt;/a&gt; / &lt;a href=&quot;https://github.com/carbonfet/dactyl-manuform&quot;&gt;Dactyl Manuform&lt;/a&gt; (many variants exists).
They’re keyboards you generate from parameters (such as number of rows and columns and the amount of curvature).
I’ve always wanted to try one and now &lt;a href=&quot;/series/voron_trident&quot;&gt;with a 3D printer&lt;/a&gt;, I can.&lt;/p&gt;
&lt;p&gt;When looking for a generator I stumbled upon the &lt;a href=&quot;https://ryanis.cool/cosmos/&quot;&gt;Cosmos keyboard configurator&lt;/a&gt; and I want to gush about it a little because &lt;mark&gt;it’s excellent&lt;/mark&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/cosmos_config.png&quot;&gt;
&lt;figcaption&gt;A relatively standard Dactyl Manuform with an encoder and trackpad.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It’s excellent because it allows a clueless sod like me to configure a keyboard the way I want to and it has an impressive feature list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Easily generate keyboards of any size.
&lt;/li&gt;
&lt;li&gt;
Customize XY-spacing, row- and colomn curvature, and more.
&lt;/li&gt;
&lt;li&gt;
Several pre-made thumb clusters.
&lt;/li&gt;
&lt;li&gt;
UI to move around all the keys.
&lt;/li&gt;
&lt;li&gt;
Supports different switches (I so need my Choc switches).
&lt;/li&gt;
&lt;li&gt;
An &lt;code&gt;Expert&lt;/code&gt; mode that allows you to customize anything via JavaScript.
&lt;/li&gt;
&lt;li&gt;
Supports encoders, trackpads, OLED displays, and trackballs.
&lt;/li&gt;
&lt;li&gt;
Can generate a wrist rest.
&lt;/li&gt;
&lt;li&gt;
Exports &lt;code&gt;.stl&lt;/code&gt; for easy printing or &lt;code&gt;.step&lt;/code&gt; you can import to CAD.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here’s a small snippet from how the code in &lt;code&gt;Expert&lt;/code&gt; mode might look like:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword declaration js&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;meta binding name js&quot;&gt;&lt;span class=&quot;variable other readwrite js&quot;&gt;curvature&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment js&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta mapping js&quot;&gt;&lt;span class=&quot;punctuation section mapping begin js&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  curvatureOfColumn&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;15&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  curvatureOfRow&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  spacingOfRows&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;18&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; 18x19 Choc spacing
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  spacingOfColumns&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;19&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  arc&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section mapping end js&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator statement js&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment block documentation js&quot;&gt;&lt;span class=&quot;punctuation definition comment begin js&quot;&gt;/**&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment js&quot;&gt;*&lt;/span&gt; Useful for setting a different curvature
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment js&quot;&gt;*&lt;/span&gt; for the pinky keys.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment end js&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword declaration js&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;meta binding name js&quot;&gt;&lt;span class=&quot;variable other readwrite js&quot;&gt;pinkyCurvature&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment js&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta mapping js&quot;&gt;&lt;span class=&quot;punctuation section mapping begin js&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword operator spread js&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;variable other readwrite js&quot;&gt;curvature&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  curvatureOfColumn&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;15&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section mapping end js&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator statement js&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment block documentation js&quot;&gt;&lt;span class=&quot;punctuation definition comment begin js&quot;&gt;/**&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment js&quot;&gt;*&lt;/span&gt; The plane used to position the upper keys.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment js&quot;&gt;*&lt;/span&gt; It&amp;#39;s rotated by the tenting and x rotation
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment js&quot;&gt;*&lt;/span&gt; then translated by the z offset.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment end js&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword declaration js&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;meta binding name js&quot;&gt;&lt;span class=&quot;variable other readwrite js&quot;&gt;upperKeysPlane&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment js&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator word new js&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;meta function-call constructor js&quot;&gt; &lt;span class=&quot;variable type js&quot;&gt;Trsf&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; `20` specifies the tenting angle.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;rotate&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;20&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language boolean false js&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;rotate&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language boolean false js&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;translate&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language boolean false js&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator statement js&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The entire state of the keyboard is also stored in the url, so I can easily share my config by including a link: &lt;a href=&quot;https://ryanis.cool/cosmos/beta#cm:CoYBChASBRCQQSATEgASADgxQIBOCg0SBRCQTSATEgASADgdChUSBRCQWSATEgASAxCwLzgJQITIvQIKFRIFEJBlIBMSABIDELA7OApAgYCcAQomEhEQkHEgE0CClKQMSP2JzLSQDBIHQICaJEiJBxIAOB5Aiq6KgAUYAECihdis8FJI3oyrwAEKQQouEhMQQCAAQMuFsI6gAki5j4i2oZILEhUIloASIABA2oPYttAKSMmjwM3g+wc4ABgCQOOLzKzwM0imqeDG8LMICo4BChASBRCQNSATEgASADgyQIBOCg0SBRCQKSATEgASADgeChkSBRCQHSATEgASABIFELBSQAQ4CkCDyL0CChkSBRCQESATEgASABIFELBQQAE4CUCCgJwBCiYSERCQBSATQIKUpAxI/YnQtJAMEgdAgJokSIkHEgA4HUCJroqABRgBQKGF2KzwUkjeiqu4AQo9CioSExBAIABAwIPontA1SLmPhLaRkgsSESAAQMyFsI6gAki5j4S2kZILOAAYA0Dki8ys8DNIpqncxoC0CBADGIYgIgYIvgEQtAE4A4IBAgQCUABYQ3IYSGSAAWRQ6AJY/giIAcwIYIQHaIQHcNAFeLyLvP7wOPIBAggB&quot;&gt;Cosmos reference of the final keyboard configuration&lt;/a&gt;.
(Barring any breaking changes in the tool of course…)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Initial-design-parameters&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Initial-design-parameters&quot; class=&quot;heading-ref&quot;&gt;Initial design parameters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even with a keyboard configurator I needed a way to start.
I already have a &lt;a href=&quot;/series/t-34&quot;&gt;layout that I really like&lt;/a&gt; so I wasn’t starting from nothing.
These were the important parts going into the design process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A 3x5 grid with 1-2 thumb keys (in practice one thumb key is enough).&lt;/p&gt;
&lt;p&gt;If you question why I want to build such a small keyboard I’ll redirect you to the discussion in &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/&quot;&gt;The T-34 keyboard layout&lt;/a&gt; post.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Integrated trackball on the right-hand side.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choc switches.&lt;/p&gt;
&lt;p&gt;One of the major decisions with a keyboard is what kind of switch to use.
While MX-style switches are the most common I personally really love Choc switches for a couple of reasons:&lt;/p&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Low-profile
&lt;/li&gt;
&lt;li&gt;
Low actuation force
&lt;/li&gt;
&lt;li&gt;
Can be closer together
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;While a low profile switch is more important for a flat keyboard, not a tented and curved one like I’m building now,
the flatter keycaps and the switches being closer together is crucial for pressing two keys with one finger:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/cosmos/compo_no_press.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/compo_no_press.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/cosmos/combo_press.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/combo_press.jpg&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;A horizontal combo is pressed with the finger in the middle of the keys. It’s surprisingly comfortable.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The low-actuation force is also more comfortable to me as it helps reduce the strain on my fingers, and makes combos (pressing several switches at once) generally more pleasant.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Hardware-and-material&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Hardware-and-material&quot; class=&quot;heading-ref&quot;&gt;Hardware and material&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s not enough with just a 3D printer, to build a working keyboard you need a bunch of hardware:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Two microcontrollers.&lt;/p&gt;
&lt;p&gt;I got the &lt;a href=&quot;https://splitkb.com/products/liatris&quot;&gt;Liatris&lt;/a&gt; microcontroller as it has enough pins to connect a trackball sensor and it supports &lt;a href=&quot;https://docs.qmk.fm/&quot;&gt;QMK&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switches&lt;/p&gt;
&lt;p&gt;What kind of Choc switch should I use?&lt;br&gt;
&lt;a href=&quot;https://splitkb.com/collections/switches-and-keycaps/products/kailh-low-profile-choc-switches?variant=42309434802435&quot;&gt;Linear&lt;/a&gt;, &lt;a href=&quot;https://splitkb.com/collections/switches-and-keycaps/products/sunset-kailh-low-profile-choc-switches&quot;&gt;tactile&lt;/a&gt;, or &lt;a href=&quot;https://splitkb.com/collections/switches-and-keycaps/products/kailh-low-profile-choc-switches?variant=39459382427725&quot;&gt;clicky&lt;/a&gt;?&lt;br&gt;
Exactly how heavy should they be?&lt;br&gt;
Should they be &lt;a href=&quot;https://splitkb.com/collections/switches-and-keycaps/products/ambients-kailh-low-profile-choc-switches&quot;&gt;silent&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;I wasn’t sure so I ordered a sampling of different switches to try.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/choc_switches.jpg&quot;&gt;
&lt;figcaption&gt;A collection of different Choc switches.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;For the final keyboard I used the &lt;a href=&quot;https://splitkb.com/collections/switches-and-keycaps/products/ambients-kailh-low-profile-choc-switches&quot;&gt;Ambients silent Noctural (linear / 20gf)&lt;/a&gt; switches,
where the deciding factor was getting as light switches as possible.
(I’ve previously used modded 15gf switches, which were even better, but I couldn’t find a way to buy them.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keycaps&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/choc_keycaps.jpg&quot;&gt;
&lt;figcaption&gt;It’s hard to decide on a colorscheme so I &lt;a href=&quot;https://splitkb.com/collections/switches-and-keycaps/products/mbk-pbt-coloured-blank-keycaps&quot;&gt;bought a bunch of random colors&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Keycaps aren’t only for looking cool.
A convex keycap for the thumb button instead of the standard concave one makes it much more comfortable:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/keycaps_concave_convex.jpg&quot;&gt;
&lt;figcaption&gt;The blue convex keycap to the left and the red concave to the right.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I also got keycaps for the index row with these small &lt;a href=&quot;https://splitkb.com/collections/switches-and-keycaps/products/mbk-pbt-coloured-blank-keycaps?variant=47289185632603&quot;&gt;homing notches&lt;/a&gt; to help my fingers more easily find the home row.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A pair of &lt;a href=&quot;https://splitkb.com/products/trrs-jacks?_pos=2&amp;amp;_sid=2fdada9a4&amp;amp;_ss=r&quot;&gt;TRRS connectors&lt;/a&gt; and a &lt;a href=&quot;https://splitkb.com/products/braided-trrs-cable?variant=31226379501645&quot;&gt;TRRS cable&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A Trackball with a matching sensor.&lt;/p&gt;
&lt;p&gt;I decided to pick up &lt;a href=&quot;https://www.tindie.com/products/citizenjoe/pmw3389-motion-sensor/&quot;&gt;this PMW3389 sensor&lt;/a&gt; because it was recommended in the keyboard configurator and &lt;a href=&quot;https://www.amazon.se/dp/B071NX7Y2J?th=1&quot;&gt;a red 34mm trackball from Amazon&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Filament for the 3D printed pieces.&lt;/p&gt;
&lt;p&gt;I ended up settling on the &lt;a href=&quot;https://www.3djake.com/polymaker/polyterra-pla-army-purple&quot;&gt;PolyTerra PLA Army Purple&lt;/a&gt; for the case but I used a bunch of different filament during the prototype phase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Diodes, screws, heatset inserts, and cable to do the wiring.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Prototypes&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Prototypes&quot; class=&quot;heading-ref&quot;&gt;Prototypes&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/prototype_cases.jpg&quot;&gt;
&lt;figcaption&gt;Some discarded prototypes.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;When you’re trying to design something like a custom keyboard I think you need to go through a bunch of trial-and-error until you find something that fits.&lt;/p&gt;
&lt;p&gt;Here’s a short rundown of some of the significant revisions I went through, mostly to illustrate that it’s very much an iterative process.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;When I first started this process the &lt;a href=&quot;https://ryanis.cool/cosmos/&quot;&gt;Cosmos&lt;/a&gt; keyboard configurator didn’t support generating both halves at the same time, so I focused on getting the right side comfortable first.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;First-print&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#First-print&quot; class=&quot;heading-ref&quot;&gt;First print&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For my first print I mostly wanted to print it out and test how a keyboard with a standard curvature felt.
I also wanted to try to place a trackball somewhere.&lt;/p&gt;
&lt;p&gt;I ended up removing a regular thumb key (I’ve used two thumb keys with my &lt;a href=&quot;/series/t-34&quot;&gt;keyboard layout&lt;/a&gt;) to make it fit and I added a “mouse thumb key” that I plan to use as a &lt;code&gt;left mouse button&lt;/code&gt; when I’m operating the trackball.
It was tricky to place the trackball as I wanted to operate it with my index + middle finger, not my thumb.&lt;/p&gt;
&lt;p&gt;Another tweak I made was to reduce the spacing between the keys to be closer to the Choc spacing.
Choc spacing seems to be 18.6 x 17.6 mm, but I used 19 x 18 mm spacing—the attraction to round numbers is real.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v2_proto.jpg&quot;&gt;
&lt;figcaption&gt;This is the very first prototype I printed.
Please ignore the bad print quality; the filament was wet and the temperature was too high. It’s just a prototype so it really doesn’t matter.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Pressing-the-top-right-key-with-the-ring-finger&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Pressing-the-top-right-key-with-the-ring-finger&quot; class=&quot;heading-ref&quot;&gt;Pressing the top right key with the ring finger&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most of the keys on the keyboard felt fine but I had one major annoyance: 
I have a habit of using the ring finger to press the top right key instead of the pinky but with the curvature on the keyboard this just wasn’t possible anymore.&lt;/p&gt;
&lt;p&gt;You might wonder, why don’t I just create a new habit and use the pinky &lt;em&gt;as you’re supposed to&lt;/em&gt;?
The simple answer is that I &lt;strong&gt;hate&lt;/strong&gt; it.
To my fingers that feels beyond terrible and I’d rather remove the key and only have two keys in the outermost column.
As it happens, pressing the key with my ring finger (on a flat keyboard) feels good so I’d rather adjust the key than remove it.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;That’s the beauty of designing a custom keyboard for yourself—you can do weird shit that only makes sense to you.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v3_proto.jpg&quot;&gt;
&lt;figcaption&gt;The second printed prototype, with some keys installed for testing.
The printer clogged before the print was finished but it did its job as a prototype.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v3_p_ring_finger.png&quot;&gt;
&lt;figcaption&gt;Here’s an angle from the configurator showing the offset of the &lt;code&gt;p&lt;/code&gt; key compared the other keys in the column.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I also added an extra mouse thumb key and lowered the pinky column a bit.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Adjust-mouse-keys-and-increase-tenting&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Adjust-mouse-keys-and-increase-tenting&quot; class=&quot;heading-ref&quot;&gt;Adjust mouse keys and increase tenting&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v6_proto.jpg&quot;&gt;
&lt;figcaption&gt;It’s starting to look like an actual keyboard.
With color coded keycaps; red for mouse-only buttons and violet for the home-row keys.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Pressing &lt;code&gt;p&lt;/code&gt; with my ring finger feels great.
Pressing the thumb normal thumb key feels awful because the mouse thumb keys are in the way when I relax my hand.&lt;/p&gt;
&lt;p&gt;Adjustments made:&lt;/p&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Moved mouse thumb keys to be more vertical and pressed from the side.
&lt;/li&gt;
&lt;li&gt;
Added an extra pinky key reachable when I’m using the trackball.
&lt;/li&gt;
&lt;li&gt;
Increased tenting to 20 degrees from 10 degrees.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v6_config.png&quot;&gt;
&lt;figcaption&gt;20 degrees of tenting.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Rounded-base-and-pinky-tweak&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Rounded-base-and-pinky-tweak&quot; class=&quot;heading-ref&quot;&gt;Rounded base and pinky tweak&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v8_proto.jpg&quot;&gt;
&lt;figcaption&gt;Yet another prototype.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
I tried the “rounded” sides and top feature of &lt;a href=&quot;https://ryanis.cool/cosmos/&quot;&gt;Cosmos&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
The mouse pinky key was too low, I raised it up a bunch.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Thumb-keys-adjustments&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Thumb-keys-adjustments&quot; class=&quot;heading-ref&quot;&gt;Thumb keys adjustments&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v9_proto.jpg&quot;&gt;
&lt;/figure&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Rotated the main thumb key inwards
&lt;/li&gt;
&lt;li&gt;
Added an area for a display
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Lowered the mouse thumb keys a little
&lt;/li&gt;
&lt;li&gt;
Removed the “rounded” features
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;More-tweaks-and-the-left-half&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#More-tweaks-and-the-left-half&quot; class=&quot;heading-ref&quot;&gt;More tweaks and the left half&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v11_proto.jpg&quot;&gt;
&lt;/figure&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Configure the left half of the keyboard
&lt;/li&gt;
&lt;li&gt;
Move pinky keys a little upwards
&lt;/li&gt;
&lt;li&gt;
Move all thumb keys a little further away
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Removed the display (felt like too much of a hassle for a little coolness)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Although I said I wanted to have a 3x5 grid, the generator included an easy option to include a small bottom row with 2 extra keys (for the ring and middle finger) that I wanted to try out for the left side.
They’re… Okay I guess.
Not crazy uncomfortable but not quite comfortable enough that I want to have common keys there.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Beta-V3&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Beta-V3&quot; class=&quot;heading-ref&quot;&gt;Beta V3&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v12_proto.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;At this point the Beta V3 of &lt;a href=&quot;https://ryanis.cool/cosmos/&quot;&gt;configurator&lt;/a&gt; is out and in it there’s several improvements, most notably:&lt;/p&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Both halves can be configured at the same time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Can go between the Advanced and Expert tabs! WOW!&lt;/p&gt;
&lt;p&gt;I had to manually keep track of the JavaScript changes I made, and update them manually if I wanted to make a change in the UI…
But no more!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;I had to redo most of the configuration and I think I made some minor changes that I didn’t keep track of, but I made two larger ones:&lt;/p&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Lowered the tenting angle to 15 degrees (from 20)
&lt;/li&gt;
&lt;li&gt;
Lowered ring pinky column key a little
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Small-tweaks-to-pinky-and-thumb-keys&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Small-tweaks-to-pinky-and-thumb-keys&quot; class=&quot;heading-ref&quot;&gt;Small tweaks to pinky and thumb keys&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/v13_proto.jpg&quot;&gt;
&lt;/figure&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Raise/tilt top pinky row key
&lt;/li&gt;
&lt;li&gt;
Move thumb keys on left side closer together
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Trackball-mounting-types&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Trackball-mounting-types&quot; class=&quot;heading-ref&quot;&gt;Trackball mounting types&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/roller_trackball.jpg&quot;&gt;
&lt;figcaption&gt;Roller bearings for the trackball.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;When I started this project &lt;a href=&quot;https://ryanis.cool/cosmos/&quot;&gt;Cosmos&lt;/a&gt; only supported a single type of trackball mount: roller bearings.
They worked quite poorly for me as the ball was spinning well in one direction but poorly in others.&lt;/p&gt;
&lt;p&gt;Luckily new options were added and as I’m writing this there’s 4 different ways you can mount the trackball:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Roller bearings (the old option)
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.aliexpress.com/item/1005005411108700.html&quot;&gt;BTU (7.5mm or 9mm)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.aliexpress.com/item/4000140404600.html&quot;&gt;Static ball bearings (3.175mm)&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because I was burned with the bad experience (and I didn’t want to rebuild the keyboard yet again) I made small prototypes of the three different options:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/trackball_types.jpg&quot;&gt;
&lt;figcaption&gt;The new trackball mounts; BTU 9mm, BTU 7.5mm, and static ball bearings.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The BTUs had the least friction and it felt really easy to spin the ball but they were also distressingly loud.
The static ball bearings had more friction than the BTUs and less than the roller bearings while being completely silent, so I chose to go with the ball bearings.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/trackball_mount.jpg&quot;&gt;
&lt;figcaption&gt;The ball bearings installed on the keyboard, with the trackball sensor peeking through.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;While they don’t feel nearly as good as the &lt;a href=&quot;https://www.kensington.com/p/products/ergonomic-desk-accessories/ergonomic-input-devices/slimblade-trackball/&quot;&gt;Kensington SlimBlade&lt;/a&gt; they’re decent enough.
I try not to use the mouse &lt;em&gt;that&lt;/em&gt; much and having the trackball so much closer is worth it compared to having a separate trackball unit besides the keyboard.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;When I discovered this issue I had already wired up the keyboard, so to switch mount I had to redo the wiring.
It was worth it.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Remove-mouse-keys&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Remove-mouse-keys&quot; class=&quot;heading-ref&quot;&gt;Remove mouse keys&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/right_complete_no_mouse_keys.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;After having used the keyboard for real I realized that the three keys dedicated to mouse buttons would have to go.
There were two major issues with them:&lt;/p&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
The pinky key got in the way sometimes when I reached for the top column, and I couldn’t retrain myself to avoid it.
&lt;/li&gt;
&lt;li&gt;
One of the goals with the &lt;a href=&quot;/series/t-34&quot;&gt;keyboard layout I use&lt;/a&gt; is to reduce the thumb and pinky usage of my right hand. The mouse keys counteract this goal.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;So I had them removed and I rewired the right half for the 3rd time.
&lt;em&gt;Sigh&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I think the lesson is that it’s not enough to print a prototype and press switches pretending to type, you have to build and &lt;em&gt;use&lt;/em&gt; the keyboard a bunch before you can evaluate some of the design decisions.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ryanis.cool/cosmos/beta#cm:CoYBChASBRCQQSATEgASADgxQIBOCg0SBRCQTSATEgASADgdChUSBRCQWSATEgASAxCwLzgJQITIvQIKFRIFEJBlIBMSABIDELA7OApAgYCcAQomEhEQkHEgE0CClKQMSP2JzLSQDBIHQICaJEiJBxIAOB5Aiq6KgAUYAECihdis8FJI3oyrwAEKQQouEhMQQCAAQMuFsI6gAki5j4i2oZILEhUIloASIABA2oPYttAKSMmjwM3g+wc4ABgCQOOLzKzwM0imqeDG8LMICo4BChASBRCQNSATEgASADgyQIBOCg0SBRCQKSATEgASADgeChkSBRCQHSATEgASABIFELBSQAQ4CkCDyL0CChkSBRCQESATEgASABIFELBQQAE4CUCCgJwBCiYSERCQBSATQIKUpAxI/YnQtJAMEgdAgJokSIkHEgA4HUCJroqABRgBQKGF2KzwUkjeiqu4AQo9CioSExBAIABAwIPontA1SLmPhLaRkgsSESAAQMyFsI6gAki5j4S2kZILOAAYA0Dki8ys8DNIpqncxoC0CBADGIYgIgYIvgEQtAE4A4IBAgQCUABYQ3IYSGSAAWRQ6AJY/giIAcwIYIQHaIQHcNAFeLyLvP7wOPIBAggB&quot;&gt;Cosmos reference&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Additional-printed-parts&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Additional-printed-parts&quot; class=&quot;heading-ref&quot;&gt;Additional printed parts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the case is the biggest and most important part of this kind of keyboard, there are a few other parts I had to print to complete the keyboard.&lt;/p&gt;
&lt;section id=&quot;Wrist-rests&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Wrist-rests&quot; class=&quot;heading-ref&quot;&gt;Wrist rests&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/prototype_rests.jpg&quot;&gt;
&lt;figcaption&gt;Some of the different wrist rests I tried.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;While they’re called a &lt;em&gt;wrist&lt;/em&gt; rests, I don’t think you should hold your arms so that there’s pressure on the wrist as that can easily lead to carpal tunnel syndrome.
Surprisingly this is even worse with a softer support but I don’t want to risk it either way.&lt;/p&gt;
&lt;p&gt;I think of them more as &lt;em&gt;palm&lt;/em&gt; rests, where I rest the lower part of the palm on the rest, making sure the wrist itself doesn’t receive any pressure.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Magnet-attachments&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#Magnet-attachments&quot; class=&quot;heading-ref&quot;&gt;Magnet attachments&lt;/a&gt;&lt;/h4&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/cosmos/magnets_in_case.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/magnets_in_case.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/cosmos/magnets_on_rest.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/magnets_on_rest.jpg&quot;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;The wrist rests didn’t come with any sort of attachment to the case, so they just always drifted away.
I tried to combat this by gluing magnets inside the case and outside the wrist rest, making them stick together just enough to stay together during normal use, while being easily removable.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;I-ended-up-not-using-the-wrist-rests&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#I-ended-up-not-using-the-wrist-rests&quot; class=&quot;heading-ref&quot;&gt;I ended up not using the wrist rests&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Despite my efforts, I haven’t been using the printed rests as I reverted to the &lt;a href=&quot;https://splitkb.com/products/crystals-gel-flexible-wrist-rest?_pos=1&amp;amp;_sid=43057db1e&amp;amp;_ss=r&quot;&gt;”squishy” ones&lt;/a&gt; I’ve used before:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/squishy_rest.jpg&quot;&gt;
&lt;figcaption&gt;It’s not visible from this angle but my hand rests using the palm instead of the wrist.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The printed felt too uncomfortable and I couldn’t find an angle I liked more than the gel rests.
Oh well.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Microcontroller-holder&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Microcontroller-holder&quot; class=&quot;heading-ref&quot;&gt;Microcontroller holder&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/microcontroller_holder.jpg&quot;&gt;
&lt;figcaption&gt;The microcontroller is held in place by a holder you screw into the case.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There’s a holder to fasten the microcontroller to the case that I use.
I had to manually make a hole to make the &lt;code&gt;Boot&lt;/code&gt; button accessible, which was easily accomplished when slicing the model.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Bottom-plate&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Bottom-plate&quot; class=&quot;heading-ref&quot;&gt;Bottom plate&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/bottom_plate.jpg&quot;&gt;
&lt;figcaption&gt;A flexible bottom plate hides the wiring.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;One problem with the &lt;a href=&quot;https://github.com/pierrechevalier83/ferris&quot;&gt;Ferris&lt;/a&gt; was that it would sometimes slip on the table.
I counteracted this by using an old Netrunner playmat but I wanted another solution.&lt;/p&gt;
&lt;p&gt;The keyboard is generated with a bottom plate that’s used to hide and protect the internals.
I printed it in TPU, a flexible and rubbery material, that gives enough grip to stay relatively still when I’m typing.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Wiring&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Wiring&quot; class=&quot;heading-ref&quot;&gt;Wiring&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/right_wiring_complete.jpg&quot;&gt;
&lt;figcaption&gt;The complete wiring of the right-side keyboard.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;section id=&quot;Matrix&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Matrix&quot; class=&quot;heading-ref&quot;&gt;Matrix&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the first things you need to do when wiring up a custom keyboard is to plan out a matrix.
I guess you could directly wire every switch directly to the controller too, but that’s not feasible if you have a larger amount of keys, so the usual thing is to use a matrix.&lt;/p&gt;
&lt;p&gt;What a matrix means is you should wire together all keys in a row and connect that to a pin on the controller, and to the same with the columns.&lt;/p&gt;
&lt;p&gt;It might look something like this:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/cosmos/left_wiring.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/left_wiring.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/cosmos/right_wiring.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/right_wiring.jpg&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;The green lines indicate columns and the purple lines indicates rows.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You should also use diodes in the matrix (for either rows or columns, I chose the rows). Pay attention to the diode direction.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/left_rows_soldered.jpg&quot;&gt;
&lt;figcaption&gt;The rows are connected with diodes and with a cable to a pin on the controller.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/right_matrix.jpg&quot;&gt;
&lt;figcaption&gt;The first matrix I soldered on the right side.
It was a lot more difficult to solder because of the awkward positions of the switches.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/right_matrix_no_mouse_keys.jpg&quot;&gt;
&lt;figcaption&gt;The 3rd matrix I soldered for the right side, this time without the challenging mouse keys.
Note that I wired it up slightly differently than in the wiring plan above because it felt more straightforward.
Exactly how you choose to construct the matrix doesn’t really matter, as long as every key has a unique row/column combination.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/left_matrix.jpg&quot;&gt;
&lt;figcaption&gt;Both the rows and columns are wired up and soldered to the controller.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The wiring is horrible, I know.&lt;/p&gt;
&lt;p&gt;I only lost one microcontroller due to a short…
With my wiring prowess I consider that a success!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Controller-wiring&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Controller-wiring&quot; class=&quot;heading-ref&quot;&gt;Controller wiring&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/microcontroller_cutoff.jpg&quot;&gt;
&lt;figcaption&gt;The right-side controller connected to the TRRS and the trackball sensor.
This was after I had removed them from my second wired right half and was preparing to rebuild it.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;It’s a good idea to plan out the pin assignments in advance.
I made the mistake of &lt;em&gt;soldering&lt;/em&gt; the wrong pins, mixing the two sets of SPI pins (you can’t use RX0 together with TX1 for example).&lt;/p&gt;
&lt;p&gt;Or you could not solder directly on the controller, like a normal person.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/liatris.webp&quot;&gt;
&lt;figcaption&gt;The pins of the &lt;a href=&quot;https://splitkb.com/products/liatris&quot;&gt;Liatris&lt;/a&gt; microcontroller.
It’s an RP2040-based controller.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Controller pin&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Connection&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Handedness (V&lt;sub&gt;CC&lt;/sub&gt; on the left keyboard and GND on the right)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;TRRS data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;3, 4, 5, 6, 7&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Matrix columns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;20, 22, 26, 27&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Matrix rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;13 (CS1)&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Trackball SS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;14 (SCK1)&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Trackball SCK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;15 (TX1)&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Trackball MOSI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;16 (RX1)&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Trackball MISO&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Although I connected trackball MT to pin 21 on the controller, the motion functionality isn’t supported for split keyboards.
I also didn’t connect RST.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/left_micro_soldered.jpg&quot;&gt;
&lt;figcaption&gt;The TRRS connector is connected to Vcc, GND, and pin 2 (and similarly on the right side).
Pin 1 is also connected to Vcc to signal to QMK that this is the left side of the keyboard, whereas pin 1 is connected to GND on the right controller.

&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/cosmos/pmw339.jpg&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;https://www.tindie.com/products/citizenjoe/pmw3389-motion-sensor/&quot;&gt;pmw3389&lt;/a&gt; sensor attached beneath the trackball.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;The trackball sensor is &lt;em&gt;very&lt;/em&gt; sensitive with the distance towards the trackball.
With my last print I had to file down the print where the sensor was attached to in order to get the sensor to track properly.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Adding-the-keyboard-to-QMK&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Adding-the-keyboard-to-QMK&quot; class=&quot;heading-ref&quot;&gt;Adding the keyboard to QMK&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The QMK cli has the &lt;code&gt;qmk new-keyboard&lt;/code&gt; command that helps you get started.
I couldn’t get the generated template to work for me, so I copied settings from an existing keybord with &lt;code&gt;rp2042&lt;/code&gt; support.&lt;/p&gt;
&lt;p&gt;I’ll try to hit on the most important parts of the config, take a &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/cybershard&quot; title=&quot;QMK source code&quot;&gt;look at the source code&lt;/a&gt; for all details.&lt;/p&gt;
&lt;section id=&quot;Basic-setup&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Basic-setup&quot; class=&quot;heading-ref&quot;&gt;Basic setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The folder structure for the keyboard looks like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;qmk_firmware&amp;#x2F;keyboards&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;cybershard
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── keyboard.json
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── rules.mk
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── halconf.h
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── mcuconf.h
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;└── keymaps
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    └── default
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ├── config.h
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ├── keymap.c
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ├── rules.mk
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        └── ...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(&lt;mark&gt;Cybershard&lt;/mark&gt; is the name I eventually settled on for the keyboard.)&lt;/p&gt;
&lt;p&gt;The most important part is &lt;code&gt;keyboard.json&lt;/code&gt; that defines (almost) everything we need for a new keyboard in QMK.&lt;/p&gt;
&lt;p&gt;First you need to set the &lt;code&gt;processor&lt;/code&gt;, &lt;code&gt;bootloader&lt;/code&gt;, and &lt;code&gt;usb&lt;/code&gt; values.
The &lt;a href=&quot;https://splitkb.com/products/liatris&quot;&gt;Liatris&lt;/a&gt; microcontroller uses the &lt;a href=&quot;https://docs.qmk.fm/platformdev_rp2040&quot;&gt;RP2040&lt;/a&gt; MCU, and I just picked some vendor- and product identifiers:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;keyboard.json&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight json&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;keyboard_name&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;cybershard&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;processor&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;RP2040&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;bootloader&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;rp2040&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;usb&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;device_version&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;0.0.1&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;pid&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;0x0002&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;vid&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;0x0361&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we need to define the matrix (with the pins we soldered) and the layout (how we’ll configure the keymap in &lt;code&gt;keymap.c&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;keyboard.json&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight json&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;diode_direction&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;COL2ROW&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix_pins&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; We need to use a `GP` prefix for the pins.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;rows&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP26&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP27&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP22&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP20&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;cols&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP3&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP4&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP5&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP6&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP7&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;layouts&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;LAYOUT&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;layout&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; First physical row
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; Second row
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; etc...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we can pick whatever physical pins we want as we can move around and configure them in software.
The &lt;code&gt;LAYOUT&lt;/code&gt; macro is what we use in &lt;code&gt;keymap.c&lt;/code&gt; to define our keymap.
When defining it we can choose to skip certain keys and reorganize it to be easier to define; for example, there’s no switch at &lt;code&gt;0,0&lt;/code&gt; in my keyboard so I skip that.&lt;/p&gt;
&lt;p&gt;The above &lt;code&gt;LAYOUT&lt;/code&gt; can then be used like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;keymap.c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;LAYOUT&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; SE_J&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_C&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_Y&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_F&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_P&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; SE_R&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_S&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_T&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_H&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_K&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; SE_COMM&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; SE_V&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_G&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_D&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_B&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          SE_A&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_B&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                            &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Thumb keys
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                            FUN_CLR&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; MT_SPC&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Flashing&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Flashing&quot; class=&quot;heading-ref&quot;&gt;Flashing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the above setup we should be able to flash the keyboard by first entering the boot loader and running:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;qmk&lt;/span&gt; flash -kb cybershard -km default
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I didn’t add a reset button to the keyboard that you typically use to enter the boot loader.
The &lt;a href=&quot;https://splitkb.com/products/liatris&quot;&gt;Liatris&lt;/a&gt; has a boot button that you can hold when you connect the keyboard, but I want to hide the controller inside the casing.&lt;/p&gt;
&lt;p&gt;QMK has a &lt;code&gt;QK_BOOT&lt;/code&gt; key that does the same.
I added it as a 5-finger &lt;a href=&quot;https://docs.qmk.fm/#/feature_combo&quot;&gt;combo&lt;/a&gt; to make it easily accessible but difficult to press by accident.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Now the process of updating the firmware is quite nice and unless I screw up I don’t need to connect another keyboard to do it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Start flashing with &lt;code&gt;qmk flash&lt;/code&gt; (it will wait until it finds a flashable target).
&lt;/li&gt;
&lt;li&gt;
Press the &lt;code&gt;QK_BOOT&lt;/code&gt; combo (the keyboard becomes unresponsive).
&lt;/li&gt;
&lt;li&gt;
Wait until the script finishes and the keyboard is available again.
&lt;/li&gt;
&lt;/ol&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;&lt;code&gt;qmk flash&lt;/code&gt; first didn’t work for me and it always got stuck at:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Flashing for bootloader: rp2040
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Waiting for drive to deploy...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After some digging around I found that the script is trying to copy a &lt;code&gt;.uf2&lt;/code&gt; file into a usb storage, and the controller will then reboot as a keyboard with &lt;em&gt;something&lt;/em&gt; like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;qmk&lt;/span&gt; compile -kb cybershard -km default
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;sudo&lt;/span&gt; mount /dev/sdX1 /media/sd
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;sudo&lt;/span&gt; cp cybershard_default.uf2 /media/sd/
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After more frustration I found out that the flash scripts looks for a file called &lt;code&gt;INFO_UF2.TXT&lt;/code&gt; under all drives mounted below &lt;code&gt;/media&lt;/code&gt;.
Because my system doesn’t mount usb drives by default the script would never find it and hang.&lt;/p&gt;
&lt;p&gt;The simple solution is to start mounting usb drives automatically, which I did by installing &lt;a href=&quot;https://ignorantguru.github.io/udevil/&quot;&gt;udevil&lt;/a&gt; and running &lt;code&gt;devmon&lt;/code&gt; on system startup.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Split-keyboard&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Split-keyboard&quot; class=&quot;heading-ref&quot;&gt;Split keyboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To get the split keyboard feature to work I had to set the &lt;code&gt;SERIAL_DRIVER&lt;/code&gt; option in &lt;code&gt;rules.mk&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rules.mk&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight make&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;variable other makefile&quot;&gt;SERIAL_DRIVER&lt;/span&gt; &lt;span class=&quot;keyword operator assignment makefile&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string unquoted makefile&quot;&gt;vendor&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And add the &lt;code&gt;split&lt;/code&gt; configuration to &lt;code&gt;keyboard.json&lt;/code&gt; and modify the &lt;code&gt;LAYOUT&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;keyboard.json&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight json&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;split&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;enabled&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant language json&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; The pin that signals if the current controller is the left (high)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; or right (low) controller.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;handedness&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;pin&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP1&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; The TRRS data pin.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;soft_serial_pin&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP2&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix_pins&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;right&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; We can override the pins for the right controller.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; Note that GP26 and GP27 are swapped compared to the left side
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; due to a mistake I made when soldering.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;rows&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP27&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP26&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP22&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP20&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;cols&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP3&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP4&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP5&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP6&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;GP7&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;transport&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;sync&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; We need to sync the matrix state to allow combos, mods, and
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; other stuff to work.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix_state&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant language json&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;layouts&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;LAYOUT&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; The rows 0 to 3 specifies rows on the left side and
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; 4 to 7 the rows on the right side.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;layout&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; These 5 keys are the first row on the left side.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; These 5 keys are the first row on the right side.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;matrix&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;x&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;y&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric json&quot;&gt;0&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment json&quot;&gt;//&lt;/span&gt; etc..
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;LAYOUT&lt;/code&gt; macro is just a function with many arguments but with the right order it can be formatted
to look similar to the physical keyboard.
For example, this is how the base layer of my keyboard could look like:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;LAYOUT&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Left side                                    // Right side
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt; SE_J&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_C&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_Y&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_F&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_P&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;       SE_X&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_W&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_O&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_U&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_DOT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; SE_R&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_S&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_T&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_H&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_K&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;       SE_M&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_N&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_A&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_I&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    REPEAT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; SE_COMM&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; SE_V&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_G&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_D&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_B&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;       SE_SLSH&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; SE_L&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;    SE_LPRN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; SE_RPRN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; SE_UNDS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; The extra two keys on the left side
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;          SE_MINS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; SE_PLUS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                            &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Left thumb keys   // Right thumb key
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                            FUN_CLR&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; MT_SPC&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;     SE_E
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Trackball&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Trackball&quot; class=&quot;heading-ref&quot;&gt;Trackball&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It took a long time for me to get the trackball working (admittedly, mostly because I soldered the pins wrong).
There’s quite a lot of documentation for QMK but curiously enough I didn’t find anything that covered the whole setup.
I arrived here by trial and error, trying to piece together parts from other keyboards into a setup that worked for me.&lt;/p&gt;
&lt;p&gt;First we need to create the files &lt;code&gt;halconf.h&lt;/code&gt; and &lt;code&gt;mcuconf.h&lt;/code&gt; (they go in the same folder as &lt;code&gt;keyboard.json&lt;/code&gt;) to enable the SPI driver:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;halconf.h&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor c&quot;&gt;&lt;span class=&quot;keyword control import c&quot;&gt;#pragma&lt;/span&gt; once
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor include c&quot;&gt;&lt;span class=&quot;keyword control import include c&quot;&gt;#include_next&lt;/span&gt; &lt;span class=&quot;string quoted other lt-gt include c&quot;&gt;&lt;span class=&quot;punctuation definition string begin c&quot;&gt;&amp;lt;&lt;/span&gt;halconf.h&lt;span class=&quot;punctuation definition string end c&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;HAL_USE_SPI&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant language c&quot;&gt;TRUE&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;mcuconf.h&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor c&quot;&gt;&lt;span class=&quot;keyword control import c&quot;&gt;#pragma&lt;/span&gt; once
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor include c&quot;&gt;&lt;span class=&quot;keyword control import include c&quot;&gt;#include_next&lt;/span&gt; &lt;span class=&quot;string quoted other lt-gt include c&quot;&gt;&lt;span class=&quot;punctuation definition string begin c&quot;&gt;&amp;lt;&lt;/span&gt;mcuconf.h&lt;span class=&quot;punctuation definition string end c&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor c&quot;&gt;&lt;span class=&quot;keyword control import c&quot;&gt;#undef&lt;/span&gt; RP_SPI_USE_SPI1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;RP_SPI_USE_SPI1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant language c&quot;&gt;TRUE&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;I enable the &lt;code&gt;SPI1&lt;/code&gt; device that uses the &lt;code&gt;CS1&lt;/code&gt;, &lt;code&gt;SCK1&lt;/code&gt;, &lt;code&gt;TX1&lt;/code&gt;, and &lt;code&gt;RX1&lt;/code&gt; pins on the controller.
If you want to use the &lt;code&gt;SPI0&lt;/code&gt; device then you must connect to the &lt;code&gt;CS0&lt;/code&gt;, &lt;code&gt;SCK0&lt;/code&gt;, &lt;code&gt;TX0&lt;/code&gt;, and &lt;code&gt;RX0&lt;/code&gt; pins instead.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;And enable the pointing device with the &lt;code&gt;pmw3389&lt;/code&gt; device driver in &lt;code&gt;rules.mk&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rules.mk&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;POINTING_DEVICE_ENABLE = yes
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;POINTING_DEVICE_DRIVER = pmw3389
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we need to add the sensor pins to &lt;code&gt;config.h&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;config.h&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; SPI1, matching mcuconf.h
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;SPI_DRIVER&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; SPID1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; The pin connections from the pmw3389 sensor
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;SPI_MISO_PIN&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; GP12&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;PMW33XX_CS_PIN&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; GP13&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;SPI_SCK_PIN&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; GP14&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;SPI_MOSI_PIN&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; GP15&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should be enough to get the sensor going, but because we have a split keyboard we need to set that up too:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;config.h&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;SPLIT_POINTING_ENABLE&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; The trackball is on the right
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;POINTING_DEVICE_RIGHT&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are some additional tweaks that I had to play with to make the trackball work well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;config.h&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; The trackball is quite sensitive to how
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; large the liftoff distance should be.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;PMW33XX_LIFTOFF_DISTANCE&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0x10&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Sets the mouse resolution, up to 16000.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;PMW33XX_CPI&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;1600&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; The directions where messed up, this fixes it.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;POINTING_DEVICE_ROTATION_270&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;POINTING_DEVICE_INVERT_X&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that I got the trackball moves the mouse as expected.&lt;/p&gt;
&lt;section id=&quot;Debug&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#Debug&quot; class=&quot;heading-ref&quot;&gt;Debug&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;As I struggled to get the trackball working I tried to use the debug output.
I’ll include it here for completeness sake:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Enable the console in &lt;code&gt;rules.mk&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rules.mk&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;CONSOLE_ENABLE = yes
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable pointing device debugging in &lt;code&gt;config.h&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;config.h&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;POINTING_DEVICE_DEBUG&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Turn on debugging in &lt;code&gt;keymap.c&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;keymap.c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;keyboard_post_init_user&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    debug_enable &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    debug_mouse &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And then run &lt;code&gt;qmk console&lt;/code&gt; from the command line.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Is-this-the-ultimate-keyboard&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Is-this-the-ultimate-keyboard&quot; class=&quot;heading-ref&quot;&gt;Is this the ultimate keyboard?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;p&gt;This keyboard is certainly the most comfortable keyboard I’ve used but it’s not close to being an “ultimate” keyboard.
Here’s a few things that might improve the keyboard:&lt;/p&gt;
&lt;ol type=&quot;i&quot;&gt;
&lt;li&gt;
&lt;p&gt;The trackball still isn’t nearly as comfortable as the &lt;a href=&quot;https://www.kensington.com/p/products/ergonomic-desk-accessories/ergonomic-input-devices/slimblade-trackball/&quot;&gt;Kensington SlimBlade&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Maybe a keyboard with a larger trackball would be better?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The extra keys on the left side are barely useful.&lt;/p&gt;
&lt;p&gt;It’s not a big deal, maybe I can find some usage for them, but to me having barely useful keys feels wrong.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There are more extra features I feel an &lt;em&gt;ultimate&lt;/em&gt; keyboard should have.&lt;/p&gt;
&lt;p&gt;The keyboard I’ve built is nice… But it’s still just a normal keyboard with a trackball.
Maybe a vibration sensor, a display, or even some LEDs?
A &lt;a href=&quot;https://github.com/scottbez1/smartknob&quot;&gt;smart knob with software-configurable endstops and detents&lt;/a&gt; would really add some weight to the moniker of an ultimate keyboard.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Next-steps&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Next-steps&quot; class=&quot;heading-ref&quot;&gt;Next steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s hard to know how good the keyboard is before I’ve put it through extensive use,
and to do that I need to settle on a keyboard layout for the keyboard.
I’ve already &lt;a href=&quot;/series/t-34&quot;&gt;designed a layout&lt;/a&gt; for a 34-key keyboard that should be fairly straightforward to adapt but I still need to figure out how to add mouse keys and what to do with the “extra” keys on the left-hand side.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&quot;/blog/2024/11/26/the_current_cybershard_layout&quot;&gt;The current Cybershard layout&lt;/a&gt; for how the keyboard layout is coming along.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>The current Cybershard layout</title><id>http://jonashietala.se/blog/2024/11/26/the_current_cybershard_layout/index.html</id><updated>2026-05-05T06:58:28+00:00</updated><link href="https://www.jonashietala.se/blog/2024/11/26/the_current_cybershard_layout" rel="alternate"/><published>2024-11-26T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is the keyboard layout I’m using for my custom keyboard &lt;a href=&quot;https://www.jonashietala.se/blog/2024/11/26/building_my_ultimate_keyboard/&quot;&gt;that I generated, printed, and hand-wired&lt;/a&gt;.
It’s a minimalistic keyboard of 35 keys and features an integrated trackball on the right-hand side.&lt;/p&gt;
&lt;p&gt;The keyboard layout started out as a direct copy of the &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout&quot; title=&quot;The current T-34 layout&quot;&gt;T-34 keyboard layout&lt;/a&gt;, with some small modifications from the 34-key keyboard T-34 was designed for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
An extra two keys on the left-hand side, in the ring and middle finger columns.
&lt;/li&gt;
&lt;li&gt;
Removed the second thumb key on the right-hand side.
&lt;/li&gt;
&lt;li&gt;
Accommodation for mouse keys and trackball handling.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While the layout has diverged since then, the design philosophy from &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/&quot; title=&quot;T-34 first post&quot;&gt;original T-34 post&lt;/a&gt; still holds true and I recommend it as it may explain why the layout looks like it does.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;The layout could pretty easily be converted to a 32-key layout by removing the two extra keys and the inner thumb key on the left-hand side.
These keys are barely used and the biggest reason I have them is that I don’t have the energy to rebuild the keyboard.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Legend&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Legend&quot; class=&quot;heading-ref&quot;&gt;Legend&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/legend.svg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I use quite a number of special features for the keys and I’ve tried to color code according to the above legend.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I made a bit of a detour and developed &lt;a href=&quot;https://codeberg.org/treeman/layout_gen&quot;&gt;my own tool&lt;/a&gt; to generate the embedded svg images in this post as the existing tools didn’t &lt;em&gt;exactly&lt;/em&gt; match my preferences.&lt;/p&gt;
&lt;p&gt;Note that I made it only for myself and it will probably break in many ways if you try to use it for your layout.
It’s also extremely ugly code…&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Layers&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Layers&quot; class=&quot;heading-ref&quot;&gt;Layers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.qmk.fm/#/feature_layers&quot; title=&quot;QMK layers&quot;&gt;Layers&lt;/a&gt; are super important for smaller keyboards and I use them a ton.&lt;/p&gt;
&lt;section id=&quot;Base&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Base&quot; class=&quot;heading-ref&quot;&gt;Base&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_BASE.svg&quot;&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
The &lt;a href=&quot;#Repeat-key&quot;&gt;repeat key&lt;/a&gt; is used to output the last pressed key.
&lt;/li&gt;
&lt;li&gt;
I shift keys using &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot; title=&quot;QMK auto shift&quot;&gt;auto shift&lt;/a&gt; (see &lt;a href=&quot;#Long-press&quot;&gt;long press&lt;/a&gt;) and &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
The letters &lt;code&gt;Z&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt;, together with a bunch of other keys, are on &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
The keys for &lt;code&gt;F2&lt;/code&gt;, &lt;code&gt;F12&lt;/code&gt; and &lt;code&gt;FUN&lt;/code&gt; are just extras and aren’t in a comfortable enough position to warrant anything more common.
&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;If you wonder why the top left and right keys are off that’s because the keyboard is built with them further away and with a different curvature than the other keys in the outer columns.
I don’t press &lt;code&gt;J&lt;/code&gt; or &lt;code&gt;.&lt;/code&gt; with my pinky but with my ring finger, leaving only two keys dedicated to the pinkies.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Swedish-overlay&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Swedish-overlay&quot; class=&quot;heading-ref&quot;&gt;Swedish overlay&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_SWE.svg&quot;&gt;
&lt;figcaption&gt;Swedish overlay.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;When I want to write Swedish I activate this layer that replaces &lt;code&gt;()_&lt;/code&gt; with &lt;code&gt;åäö&lt;/code&gt;, or I use &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; from any layer.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Symbols&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Symbols&quot; class=&quot;heading-ref&quot;&gt;Symbols&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_SYM.svg&quot;&gt;
&lt;figcaption&gt;Symbols layer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I typically use &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; to output symbols (following the same layout pattern as the symbols layer).
The symbols layer is mostly used to roll symbol pairs like &lt;code&gt;{}&lt;/code&gt; or &lt;code&gt;#[&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Some common symbol sequences (like &lt;code&gt;-&amp;gt;&lt;/code&gt;, &lt;code&gt; != &lt;/code&gt;, or &lt;code&gt;```&lt;/code&gt;) exists as &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; and others as &lt;a href=&quot;#Long-press&quot;&gt;long press&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Numbers&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Numbers&quot; class=&quot;heading-ref&quot;&gt;Numbers&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_NUM.svg&quot;&gt;
&lt;figcaption&gt;Numbers layer. The browner keys (like &lt;code&gt;J&lt;/code&gt;) turn off &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;While I can activate the number layer persistently (using &lt;a href=&quot;#Leader-sequences&quot;&gt;leader sequences&lt;/a&gt;) I typically use &lt;a href=&quot;#Thumb-key-combos&quot;&gt;combos&lt;/a&gt; for single digits (like &lt;code&gt;0&lt;/code&gt;), or &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; for larger numbers (like &lt;code&gt;1984&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; makes the number layer smart, so it will deactivate when certain keys are pressed.
It’s used to type numbers in text or code and for relative movement in Neovim, where &lt;code&gt;17J&lt;/code&gt; would move 17 lines down and then turn off the number layer.
Jumping directly to a line in Neovim with &lt;code&gt;12G&lt;/code&gt; is also made convenient.&lt;/p&gt;
&lt;p&gt;If I want to enter the layer without it turning off I can either use &lt;a href=&quot;#Leader-sequences&quot;&gt;leader sequences&lt;/a&gt; to activate it persistently or hold the &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; &lt;a href=&quot;#Combos-over-keyboard-halfs&quot;&gt;combo&lt;/a&gt; (hold both thumbs).
The layer won’t release until both thumb keys are released, so &lt;code&gt;Space&lt;/code&gt; can be tapped with the left thumb without leaving the number layer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@u&lt;/code&gt; is there to easily activate macros in Neovim. For example &lt;code&gt;7@u&lt;/code&gt; in the number layer would run the &lt;code&gt;u&lt;/code&gt; macro 7 times and then turn off &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Function-keys&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Function-keys&quot; class=&quot;heading-ref&quot;&gt;Function keys&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_FUN.svg&quot;&gt;
&lt;figcaption&gt;Function keys.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
The function keys follow the same layout as the &lt;a href=&quot;#Numbers&quot;&gt;numbers layer&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
The trackball &lt;code&gt;DPI&lt;/code&gt; can be lowered and raised at runtime.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Navigation-layers&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Navigation-layers&quot; class=&quot;heading-ref&quot;&gt;Navigation layers&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_NAV.svg&quot;&gt;
&lt;figcaption&gt;Navigation layer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Left&lt;/code&gt;/&lt;code&gt;Middle&lt;/code&gt;/&lt;code&gt;Right&lt;/code&gt; &lt;code&gt;Display&lt;/code&gt; are used to switch between displays in my window manager.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This layer is commonly used in conjunction with the trackball, giving access to mouse keys.&lt;/p&gt;
&lt;p&gt;For instance, &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;Left Mouse&lt;/code&gt; can be used to drag, &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;A&lt;/code&gt; to select, and &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;C&lt;/code&gt; to copy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tabbing is for switching browser tabs and the &lt;code&gt;Back&lt;/code&gt; / &lt;code&gt;Fwd&lt;/code&gt; mouse buttons goes backwards and forwards in history.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Ctrl&lt;/code&gt; + arrow is used to switch windows in Neovim.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;D&lt;/code&gt; and &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;U&lt;/code&gt; are used in Neovim to scroll half a screen (compared to &lt;code&gt;PgUp&lt;/code&gt;/&lt;code&gt;PgDn&lt;/code&gt; that scrolls an entire screen).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&quot;#Workspace-layer&quot;&gt;workspace layer&lt;/a&gt; is triggered by first holding &lt;code&gt;Space&lt;/code&gt;, and then holding the right thumb key (&lt;code&gt;WNAV&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_ARROW.svg&quot;&gt;
&lt;figcaption&gt;Arrows on the left-hand side.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This layer exists for the rare occasions I want to navigate using only the left hand.&lt;/p&gt;
&lt;p&gt;The keys on the right side is there just because and are rarely, if ever, used.
I typically use &lt;a href=&quot;#Long-press&quot;&gt;long press&lt;/a&gt; for shift and &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; for other modifiers, the modifiers here is a fallback when those aren’t enough (but honestly, I can’t remember the last time I used them).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Niri-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Niri-layer&quot; class=&quot;heading-ref&quot;&gt;Niri layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_NIRI.svg&quot;&gt;
&lt;figcaption&gt;Keys used to control my window manager &lt;a href=&quot;https://github.com/niri-wm/niri&quot;&gt;Niri&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I’m in the middle of migrating to &lt;a href=&quot;https://github.com/niri-wm/niri&quot;&gt;Niri&lt;/a&gt; instead of &lt;a href=&quot;https://xmonad.org/&quot; title=&quot;Xmonad&quot;&gt;xmonad&lt;/a&gt; and this is the layout I’m currently working on.
I plan to replace my 3-monitor setup with a single super ultrawide, so this layout is still very much in flux.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Workspace-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Workspace-layer&quot; class=&quot;heading-ref&quot;&gt;Workspace layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_WNAV.svg&quot;&gt;
&lt;figcaption&gt;Workspace layer. All keys have an implicit &lt;code&gt;Gui&lt;/code&gt; modifier.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This is used for all window and workspace management in &lt;a href=&quot;https://xmonad.org/&quot; title=&quot;Xmonad&quot;&gt;xmonad&lt;/a&gt; / &lt;a href=&quot;https://github.com/niri-wm/niri&quot;&gt;Niri&lt;/a&gt;. Some common operations are also on the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt;.
&lt;a href=&quot;#Long-press&quot;&gt;Auto shift&lt;/a&gt; works and can used to send a window to another workspace (&lt;code&gt;Gui&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;2&lt;/code&gt;).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Windows-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Windows-layer&quot; class=&quot;heading-ref&quot;&gt;Windows layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_WIN.svg&quot;&gt;
&lt;figcaption&gt;Windows layer. All keys have an implicit &lt;code&gt;Alt&lt;/code&gt; modifier.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This is purely to enable window switching using &lt;code&gt;Alt-Tab&lt;/code&gt; and &lt;code&gt;Ctrl-Alt-Tab&lt;/code&gt;, without releasing &lt;code&gt;Alt&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Mouse-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Mouse-layer&quot; class=&quot;heading-ref&quot;&gt;Mouse layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_MOUSE.svg&quot;&gt;
&lt;figcaption&gt;The mouse layer for right-hand only usage.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I generally prefer to use the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt;, where the mouse buttons are on the left side, but in some cases I’d like to only use my right hand.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Special-characters&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Special-characters&quot; class=&quot;heading-ref&quot;&gt;Special characters&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_SPEC.svg&quot;&gt;
&lt;figcaption&gt;Specials layer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_key&quot; title=&quot;Dead keys&quot;&gt;dead keys&lt;/a&gt; add diacritic to any letter. For example, to get &lt;code&gt;é&lt;/code&gt; you can use the dead key &lt;code&gt;´&lt;/code&gt; then &lt;code&gt;e&lt;/code&gt;, and the operating system will merge them together.
(&lt;code&gt;É&lt;/code&gt; also exists as a &lt;a href=&quot;#Combos&quot;&gt;combo&lt;/a&gt;.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Gaming&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Gaming&quot; class=&quot;heading-ref&quot;&gt;Gaming&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_GAME.svg&quot;&gt;
&lt;figcaption&gt;My gaming layer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_GAME2.svg&quot;&gt;
&lt;figcaption&gt;&lt;code&gt;GAME2&lt;/code&gt;, the right half of a QWERTY keyboard.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_GNUM.svg&quot;&gt;
&lt;figcaption&gt;&lt;code&gt;GNUM&lt;/code&gt;, numbers on the left-hand side.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/_GFUN.svg&quot;&gt;
&lt;figcaption&gt;&lt;code&gt;GFUN&lt;/code&gt;, function keys on the left-hand side.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I’m not a heavy gamer by any means but this setup allows me to play some games well enough.
By necessity this layer disables &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot; title=&quot;QMK auto shift&quot;&gt;auto shift&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Combos&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Combos&quot; class=&quot;heading-ref&quot;&gt;Combos&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.qmk.fm/#/feature_combo&quot; title=&quot;QMK combos&quot;&gt;Combos&lt;/a&gt; is another fantastic tool that I (ab)use a lot. Simply put it allows you to press multiple keys at once and acts as another key—very useful for smaller layouts.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;These combos are layer independent, and work regardless of what layers are activated.
The base layer is shown in the graphics for reference.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Neighbour-combos&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Neighbour-combos&quot; class=&quot;heading-ref&quot;&gt;Neighbour combos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These combos are made by keys next to each other, either horizontally (pressed with two fingers) or vertically (pressed with one finger in the middle of two keys).&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/neighbour_combos.svg&quot;&gt;
&lt;figcaption&gt;2-key neighboring combos.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
Some combos have a separate hold behaviour; for instance holding &lt;code&gt;Escape&lt;/code&gt; activates the &lt;a href=&quot;#Symbols&quot;&gt;symbols layer&lt;/a&gt;, allowing me to output &lt;code&gt;[]&lt;/code&gt; easily.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vsplit&lt;/code&gt; splits a window vertically in Neovim and &lt;code&gt;hsplit&lt;/code&gt; splits it horizontally, and &lt;code&gt;Close Window&lt;/code&gt; closes a window in Neovim (&lt;code&gt;&amp;lt;C-w&amp;gt;q&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Clear&lt;/code&gt; resets all states; sets the &lt;a href=&quot;#Base&quot;&gt;base&lt;/a&gt; layer, releases modifiers, stops &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt; and &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt;, and clears other persistent states.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;M&lt;/code&gt; is the shortcut to mute/unmute in Teams.
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/mid_triple_combos.svg&quot;&gt;
&lt;figcaption&gt;3-key horizontal combos.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SWE&lt;/code&gt; activates the &lt;a href=&quot;#Swedish-overlay&quot;&gt;Swedish layer&lt;/a&gt;, and if prefixed with &lt;code&gt;()_&lt;/code&gt; it will replace that with &lt;code&gt;åäö&lt;/code&gt; and vice versa. So for example if I typed &lt;code&gt;hall(&lt;/code&gt; I would press &lt;code&gt;SWE&lt;/code&gt; to get &lt;code&gt;hallå&lt;/code&gt;, with the Swedish layer activated.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl W&lt;/code&gt; is used to close tabs in Firefox.
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/save_vim.svg&quot;&gt;
&lt;figcaption&gt;A 4-key horizontal combo.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Save Neovim&lt;/code&gt; is a 4-key combo that saves the buffer in Neovim.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Split-combos&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Split-combos&quot; class=&quot;heading-ref&quot;&gt;Split combos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These split combos uses the ring and index finger.&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/quotes.svg&quot;&gt;
&lt;figcaption&gt;Combos for the quotes &lt;code&gt;&quot;&lt;/code&gt; and &lt;code&gt;&apos;&lt;/code&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/angled.svg&quot;&gt;
&lt;figcaption&gt;Combos don’t have to be on the same row, these angled combos are fairly comfortable.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/split_top.svg&quot;&gt;
&lt;figcaption&gt;One-shot &lt;code&gt;Alt&lt;/code&gt; on the left combo and holding the right combo activates the &lt;a href=&quot;#Windows-layer&quot;&gt;windows&lt;/a&gt; layer (with implicit &lt;code&gt;Alt&lt;/code&gt;).
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/split_lower.svg&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://docs.qmk.fm/#/feature_leader_key&quot; title=&quot;QMK leader key&quot;&gt;Leader key&lt;/a&gt; on the bottom row.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Combos-over-keyboard-halfs&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Combos-over-keyboard-halfs&quot; class=&quot;heading-ref&quot;&gt;Combos over keyboard halfs&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/smart_layers.svg&quot;&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
Tapping &lt;code&gt;T&lt;/code&gt; + &lt;code&gt;A&lt;/code&gt; once activates &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt;, tapping again makes it persistent (&lt;code&gt;CAPS LOCK&lt;/code&gt;), and a third tap to deactivate &lt;code&gt;CAPS LOCK&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Tapping &lt;code&gt;Space&lt;/code&gt; + &lt;code&gt;E&lt;/code&gt; activates &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; and tapping them again activates the &lt;a href=&quot;#Numbers&quot;&gt;number layer&lt;/a&gt; persistently.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;#Repeat-key&quot;&gt;repeat key&lt;/a&gt; works with the above, making them easier to double-tap.&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/swap_unds_mins_c.svg&quot;&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
Swaps &lt;code&gt;_&lt;/code&gt; and &lt;code&gt;-&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/specials.svg&quot;&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
Access the &lt;a href=&quot;#Special-characters&quot;&gt;specials&lt;/a&gt; layer with the ring fingers.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Thumb-key-combos&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Thumb-key-combos&quot; class=&quot;heading-ref&quot;&gt;Thumb key combos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I have a bunch of 2-key &lt;code&gt;thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt; combos:&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/MT_SPC.svg&quot;&gt;
&lt;figcaption&gt;Combos using &lt;code&gt;Space&lt;/code&gt; and another key.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/SE_E.svg&quot;&gt;
&lt;figcaption&gt;Combos using &lt;code&gt;E&lt;/code&gt; and another key.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The logic here is that &lt;code&gt;same-side thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt; = &lt;code&gt;symbol&lt;/code&gt; and &lt;code&gt;opposite-side thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt; = &lt;code&gt;digit&lt;/code&gt;, following the placements of the &lt;a href=&quot;#Numbers&quot;&gt;numbers&lt;/a&gt;, &lt;a href=&quot;#Symbols&quot;&gt;symbols&lt;/a&gt; and &lt;a href=&quot;#Swedish-overlay&quot;&gt;swedish&lt;/a&gt; layers. They’re used if I want to just type a single character, without having to activate a layer first.&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/FUN.svg&quot;&gt;
&lt;figcaption&gt;Combos using &lt;code&gt;FUN&lt;/code&gt; and another key.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I have similar combos for the &lt;a href=&quot;#Function-keys&quot;&gt;function keys&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;QMK-boot&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#QMK-boot&quot; class=&quot;heading-ref&quot;&gt;QMK boot&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/cybershard-layout/boot.svg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The keycode &lt;code&gt;QMK_BOOT&lt;/code&gt; enters boot mode for the microcontroller connected via USB, making it easy to update the keymap on the keyboard.
These two 5-key combos (one for each half) are almost impossible to trigger accidentally while being easily accessible.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Additional-features&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Additional-features&quot; class=&quot;heading-ref&quot;&gt;Additional features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;https://docs.qmk.fm/#/feature_layers&quot; title=&quot;QMK layers&quot;&gt;layers&lt;/a&gt; and &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; are the two main features I use, &lt;a href=&quot;https://docs.qmk.fm/&quot; title=&quot;QMK&quot;&gt;QMK&lt;/a&gt; has a lot of other nifty features (and you roll your own implementation of them too).&lt;/p&gt;
&lt;section id=&quot;Long-press&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Long-press&quot; class=&quot;heading-ref&quot;&gt;Long press&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most keys have a different behaviour when tapped compared to a long press. Most commonly I use this to produce shifted keys (called &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot; title=&quot;QMK auto shift&quot;&gt;auto shift&lt;/a&gt;).
So tapping the &lt;code&gt;A&lt;/code&gt; key will output &lt;code&gt;a&lt;/code&gt; as normal and if it it &lt;code&gt;A&lt;/code&gt; will appear instead.&lt;/p&gt;
&lt;p&gt;There are a bunch of special cases as well (many on top of &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt;):&lt;/p&gt;
&lt;table class=&quot;center&quot;&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Tap&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Long press&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;_&lt;/code&gt; &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;\&lt;/code&gt; &lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Double, e.g &lt;code&gt;__&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;&quot;&lt;/code&gt; &lt;code&gt;&apos;&lt;/code&gt; &lt;code&gt;=&lt;/code&gt; &lt;code&gt;`&lt;/code&gt; &lt;code&gt;0&lt;/code&gt; &lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Triple, e.g &lt;code&gt;&quot;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;|&lt;/code&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Double with spaces, e.g &lt;code&gt; || &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt; != &lt;/code&gt; (with spaces)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;{:?}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;{:#?}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;%{}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;(&lt;/code&gt; &lt;code&gt;[&lt;/code&gt; &lt;code&gt;{&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Close and move cursor between&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;@u&lt;/code&gt; (paired with &lt;code&gt;qu&lt;/code&gt; combo for Neovim macro execution)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section id=&quot;Leader-sequences&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Leader-sequences&quot; class=&quot;heading-ref&quot;&gt;Leader sequences&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I use the combo &lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt; as the &lt;a href=&quot;https://docs.qmk.fm/#/feature_leader_key&quot; title=&quot;QMK leader key&quot;&gt;leader key&lt;/a&gt;.
This will wait for a sequence of key presses (in contrast to combos where keys must be pressed at the same time).
I use this with mnemonics for rarely used outputs:&lt;/p&gt;
&lt;table class=&quot;center&quot;&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Leader sequence&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/strong&gt;aps lock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;S&lt;/strong&gt;wedish input in Linux (mapped in &lt;a href=&quot;https://xmonad.org/&quot; title=&quot;Xmonad&quot;&gt;xmonad&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/strong&gt;oggle &lt;strong&gt;&lt;strong&gt;N&lt;/strong&gt;&lt;/strong&gt;umber layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/strong&gt;oggle &lt;strong&gt;&lt;strong&gt;S&lt;/strong&gt;&lt;/strong&gt;ymbols layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;f&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/strong&gt;oggle &lt;strong&gt;&lt;strong&gt;F&lt;/strong&gt;&lt;/strong&gt;unction layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/strong&gt;oggle &lt;strong&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/strong&gt;aps lock escape swap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Ctrl&lt;/code&gt; &lt;code&gt;Shift&lt;/code&gt; &lt;strong&gt;&lt;strong&gt;Esc&lt;/strong&gt;&lt;/strong&gt;ape&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section id=&quot;CAPSWORD&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#CAPSWORD&quot; class=&quot;heading-ref&quot;&gt;CAPSWORD&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;CAPSWORD is a “smart caps lock”. It works like a regular caps lock, except it automatically turns off after certain keys are typed (most commonly space).&lt;/p&gt;
&lt;p&gt;It will not turn off on letters, numbers, &lt;code&gt;_&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;Backspace&lt;/code&gt; and the &lt;code&gt;Repeat&lt;/code&gt; keys.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;NUMWORD&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#NUMWORD&quot; class=&quot;heading-ref&quot;&gt;NUMWORD&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;NUMWORD is a “smart layer”. It’s similar to &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt;, except it activates and then turns off the &lt;a href=&quot;#Numbers&quot;&gt;numbers layer&lt;/a&gt; instead of caps lock.&lt;/p&gt;
&lt;p&gt;It will not turn off on these keys: &lt;code&gt;0-9&lt;/code&gt; &lt;code&gt;%&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;+&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;_&lt;/code&gt; &lt;code&gt;.&lt;/code&gt; &lt;code&gt;,&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;=&lt;/code&gt; &lt;code&gt;x&lt;/code&gt; &lt;code&gt;Backspace&lt;/code&gt; &lt;code&gt;Enter&lt;/code&gt; and the &lt;code&gt;Repeat&lt;/code&gt; keys.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Repeat-key&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Repeat-key&quot; class=&quot;heading-ref&quot;&gt;Repeat key&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The repeat key simply repeats the previous key. So to type &lt;code&gt;fall&lt;/code&gt; I can type &lt;code&gt;f&lt;/code&gt; &lt;code&gt;a&lt;/code&gt; &lt;code&gt;l&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt;, using four different fingers instead of pressing &lt;code&gt;l&lt;/code&gt; twice. It can also repeat things like &lt;code&gt;Ctrl-c&lt;/code&gt; or &lt;code&gt;Delete&lt;/code&gt;, and unlike regular keys that use &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot; title=&quot;QMK auto shift&quot;&gt;auto shift&lt;/a&gt; the &lt;code&gt;Repeat&lt;/code&gt; key can be held.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Trackball&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Trackball&quot; class=&quot;heading-ref&quot;&gt;Trackball&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The trackball is normally configured to move the mouse as a regular trackball.&lt;/p&gt;
&lt;p&gt;There are different modes that alters the behavior of the trackball:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Lower the DPI when &lt;code&gt;Space&lt;/code&gt; or &lt;code&gt;_&lt;/code&gt; are held (the mouse moves slower when the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt; or the &lt;a href=&quot;#Mouse-layer&quot;&gt;mouse layer&lt;/a&gt; are active).
&lt;/li&gt;
&lt;li&gt;
Raise the DPI when the &lt;a href=&quot;#Neighbour-combos&quot;&gt;&lt;code&gt;MOD&lt;/code&gt; combo&lt;/a&gt; is held (the mouse moves faster).
&lt;/li&gt;
&lt;li&gt;
Scroll instead of moving the mouse when the &lt;a href=&quot;#Neighbour-combos&quot;&gt;&lt;code&gt;SYM&lt;/code&gt; combo&lt;/a&gt; is held.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;More-info&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#More-info&quot; class=&quot;heading-ref&quot;&gt;More info&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Read the &lt;a href=&quot;/series/t-34/&quot; title=&quot;The T-34 keyboard layout&quot;&gt;T-34 series&lt;/a&gt; for the design process and motivations of my other keyboard layout (it’s the same layout with minor refinements and additions).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;See the post &lt;a href=&quot;https://www.jonashietala.se/blog/2024/11/26/building_my_ultimate_keyboard/&quot;&gt;Building my ultimate keyboard&lt;/a&gt; for how I designed and built the keyboard I’m using this layout with.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For implementation details and the most up-to-date reference check out the layout’s &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/cybershard&quot; title=&quot;QMK source code&quot;&gt;QMK source code&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;I use a bunch of custom re-implementations of existing QMK functionality and it’s probably not a good idea to copy them.
They’re there for various reasons, such as &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt; not being integrated into QMK when I started using it and I can’t be bothered to migrate over.&lt;/p&gt;
&lt;p&gt;The code is super messy and in desperate need of refactoring…&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/section&gt;
&lt;section class=&quot;changelog&quot;&gt;&lt;hr /&gt;&lt;ul class=&quot;items&quot;&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2024-11-19T00:00:00Z&quot; title=&quot;November 19, 2024&quot;&gt;November 19, 2024&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Copied the &lt;a href=&quot;/series/t-34/&quot; title=&quot;The T-34 keyboard layout&quot;&gt;T-34&lt;/a&gt; layout and adapted it for the new keyboard by adding a mouse layer, remove the shortcut layer, and changed the activation of the specials layer.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2024-11-22T00:00:00Z&quot; title=&quot;November 22, 2024&quot;&gt;November 22, 2024&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Moved &lt;code&gt;-&lt;/code&gt; to an angled combo, moving the &lt;code&gt;WIN&lt;/code&gt; key to the top row,
and move &lt;code&gt;%&lt;/code&gt; to the home-row and &lt;code&gt;!&lt;/code&gt; to the bottom row.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2024-11-23T00:00:00Z&quot; title=&quot;November 23, 2024&quot;&gt;November 23, 2024&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Reworked the mouse layer and use a more advanced triggering mechanism to be more explicit about when the layer is turned on and off.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2024-11-25T00:00:00Z&quot; title=&quot;November 25, 2024&quot;&gt;November 25, 2024&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Added double-tap functionality to &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; and &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt; &lt;a href=&quot;#Combos-over-keyboard-halfs&quot;&gt;combos&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2024-11-26T00:00:00Z&quot; title=&quot;November 26, 2024&quot;&gt;November 26, 2024&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;ol&gt;
&lt;li&gt;
Moved &lt;code&gt;-&lt;/code&gt; back to it’s original position and placed &lt;code&gt;%&lt;/code&gt; on the angled combo.
&lt;/li&gt;
&lt;li&gt;
Experimental functionality to swap &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt; for the languages that use &lt;code&gt;kebab-case&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Removed the mouse layer and placed mouse buttons on the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2024-12-03T00:00:00Z&quot; title=&quot;December  3, 2024&quot;&gt;December  3, 2024&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Reworked the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt; to keep the original positions for &lt;code&gt;PgUp&lt;/code&gt;, &lt;code&gt;PgDn&lt;/code&gt;, and &lt;code&gt;Tab&lt;/code&gt;s.
To allow this I moved the mouse click to index finger and demoted the &lt;code&gt;up&lt;/code&gt;/&lt;code&gt;down&lt;/code&gt; to the top row.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2025-01-12T00:00:00Z&quot; title=&quot;January 12, 2025&quot;&gt;January 12, 2025&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Reworked the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt; to be more focused on two hands on the board.
The idea is to use better placed keys on the right-hand side instead of cramming in too much on the left.
Moved &lt;code&gt;PgUp&lt;/code&gt; and &lt;code&gt;Home&lt;/code&gt; to the right side and it’s enough to use the arrow keys on the right. (The secondary navigation layer exists to enable arrow keys on the left side.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added mouse button combos on the right-hand side so in a pinch I can operate the mouse with one hand.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2025-01-14T00:00:00Z&quot; title=&quot;January 14, 2025&quot;&gt;January 14, 2025&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Removed mouse button combos from the right-side and place them on a separate layer instead (to keep the shift combo in the regular place).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;code&gt;Gui&lt;/code&gt; + &lt;code&gt;,&lt;/code&gt;/&lt;code&gt;.&lt;/code&gt; for &lt;a href=&quot;https://xmonad.org/&quot; title=&quot;Xmonad&quot;&gt;xmonad&lt;/a&gt; master window management to the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt;, moving &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;A&lt;/code&gt; to the home-row once again.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2025-01-20T00:00:00Z&quot; title=&quot;January 20, 2025&quot;&gt;January 20, 2025&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Added the &lt;a href=&quot;#Gaming&quot;&gt;gaming layer&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2025-12-22T00:00:00Z&quot; title=&quot;December 22, 2025&quot;&gt;December 22, 2025&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Expanded the &lt;a href=&quot;#Gaming&quot;&gt;gaming setup&lt;/a&gt; with more than one layer to be more complete, giving access to most of a regular keyboard.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2026-05-05T00:00:00Z&quot; title=&quot;May  5, 2026&quot;&gt;May  5, 2026&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;A first draft of the &lt;a href=&quot;#Niri-layer&quot;&gt;Niri layer&lt;/a&gt; for use with the window manager &lt;a href=&quot;https://github.com/niri-wm/niri&quot;&gt;Niri&lt;/a&gt;, replacing &lt;a href=&quot;https://xmonad.org/&quot; title=&quot;Xmonad&quot;&gt;xmonad&lt;/a&gt;.
Bunch of keys were removed from the &lt;a href=&quot;#Navigation-layers&quot;&gt;navigation layer&lt;/a&gt; as I instead have a dedicated layer.
It’s accessed by holding down the &lt;code&gt;Tab&lt;/code&gt; combo and extra modifiers were instead moved to the &lt;a href=&quot;#Navigation-layers&quot;&gt;Arrow&lt;/a&gt; layer.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
</content></entry><entry><title>Why I don&apos;t rely on AI for programming (too much)</title><id>http://jonashietala.se/blog/2024/10/31/why_i_dont_rely_on_ai_for_programming_too_much/index.html</id><updated>2024-10-31T08:31:27+00:00</updated><link href="https://www.jonashietala.se/blog/2024/10/31/why_i_dont_rely_on_ai_for_programming_too_much" rel="alternate"/><published>2024-10-31T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;I find that ai can help significantly with doing plumbing, but it has no problems with connecting the pipes wrong. I need to double and triple check the updated code - or fix the resulting errors when I don’t do that.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=41988665&quot;&gt;thih9 on Hacker News&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;I’ve been skeptical of the AI craze that’s been going on in the developer community.
It’s a useful tool but some people behave like large swaths of developers will be replaced by AI tomorrow.&lt;/p&gt;
&lt;p&gt;I don’t understand the hype as my experience has been quite different, yet I’ve struggled to pinpoint why.
In this post post I’ll try to explain what I think is the fundamental problem I have with letting an AI generate code for me.&lt;/p&gt;
&lt;section id=&quot;Im-bad-at-double-checking-code&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Im-bad-at-double-checking-code&quot; class=&quot;heading-ref&quot;&gt;I’m bad at double-checking code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I realized what my problem with AI is when I read this comment on Hacker News (emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;My theory is the willingness to baby sit and the modality. I’m perfectly fine telling the tool I use its errors and working side by side with it like it was another person. At the end of the day it can belt out lines of code faster than I, or any human, can and &lt;strong&gt;I can review code very quickly&lt;/strong&gt; so the overall productivity boost has been great.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=41989760&quot;&gt;ianbutler on Hacker News&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s true that I’m not fond of pair programming but the key issue is that I &lt;ins&gt;can’t&lt;/ins&gt; review code quickly.
On the contrary I’m quite bad at looking at an unknown piece of code and verify that it’s correct.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I’m specifically talking about &lt;em&gt;verifying&lt;/em&gt; code, not on figuring out what the code is trying to do or even the intent behind the code, which I think I’m relatively decent at.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Struggling-to-verify-math-problems&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Struggling-to-verify-math-problems&quot; class=&quot;heading-ref&quot;&gt;Struggling to verify math problems&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This isn’t a problem of mine that’s unique for programming.
I’ve been quite good at math (relatively speaking) since I was a child and I breezed through the University math (where I read as many math courses I could get my hands on).&lt;/p&gt;
&lt;p&gt;Despite my relative skills I &lt;em&gt;always&lt;/em&gt; got marks against me during tests and exams.
They weren’t caused by my lack of understanding but by small mistakes like writing numbers wrong.
Mistakes that I tried hard to correct; I started to double-check and triple-check my work but they were still slipping through.&lt;/p&gt;
&lt;p&gt;I realized that when I was first solving the problem I was focused.
I was &lt;em&gt;in the zone&lt;/em&gt; and I could keep the problem in my head while I worked.&lt;/p&gt;
&lt;p&gt;But when I went back to verify my work my brain wouldn’t engage in the same way.
I was trying to but I couldn’t get into the zone.
The problem was Done™ and it was like my brain had disengaged.
If I was looking at myself in a third-person view I’m sure my eyes would glaze over.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Yeah, maybe I’m not that good at math.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Its-hard-to-read-code-without-a-mental-model&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Its-hard-to-read-code-without-a-mental-model&quot; class=&quot;heading-ref&quot;&gt;It’s hard to read code without a mental model&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When we write code or solve math problems I think we build up a mental model of the problem we’re trying to solve and the system we’re interacting with;
what a variable name signifies, what effects a function call might have, and how pieces of information relate to one another.&lt;/p&gt;
&lt;p&gt;This mental model is crucial when reading code or solving math problems and if it’s missing we need to rebuild it.
I think this is what happened when I had finished my math problems: when I was finished I dropped the model, so coming back to it was a struggle.&lt;/p&gt;
&lt;p&gt;The same is true when reviewing code; you’ll be much more effective when reviewing small changes to a code base you’re familiar with because you already have a mental model of the surrounding systems.
It becomes harder when you’re reviewing larger changes, or reviewing changes in an unfamiliar code base, because you have more gaps in your mental model.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;I-struggle-to-properly-review-code&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#I-struggle-to-properly-review-code&quot; class=&quot;heading-ref&quot;&gt;I struggle to properly review code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Maybe it’s a skill issue but I find it much more difficult to find errors in code others write (or I myself wrote a while ago) than to find errors while I’m developing the code.
I get the same “eye glazes over” feeling as when I went back to verify my math problems.
I’m slow, I know I’m not doing a good job, and it’s a struggle.&lt;/p&gt;
&lt;p&gt;I truly wonder how other people review code in a productive way.
Sometimes I feel I need to run, change, and test the code to understand it… But that’s time consuming especially as the amount of code increases.
Trusting your fellow developers seems like a necessity.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;AI-generated-code-requires-careful-verification&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#AI-generated-code-requires-careful-verification&quot; class=&quot;heading-ref&quot;&gt;AI generated code requires careful verification&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some are enamored with how great AI code generation is.
And to be sure, compared to just a few years ago it’s &lt;em&gt;unbelievably&lt;/em&gt; good.
But would I trust the code as much as I’d trust a co-worker? Absolutely not.&lt;/p&gt;
&lt;p&gt;In my experience an AI is &lt;em&gt;at best&lt;/em&gt; as good as a new developer, often much worse, and sometimes outright horrible.
(And no, I don’t blindly trust a new developer. I don’t trust myself either.)
At least I can be reasonably sure that other developers test or run their code before I need to look at it.&lt;/p&gt;
&lt;p&gt;Relying on AI is like copy pasting code from &lt;a href=&quot;https://stackoverflow.com/&quot;&gt;Stack Overflow&lt;/a&gt;: useful but you cannot trust it.
While the code may look good on a surface level, it’s often subtly wrong in ways that even a &lt;a href=&quot;https://stackoverflow.com/&quot;&gt;Stack Overflow&lt;/a&gt; answer doesn’t quite manage to.
Hallucinating a non existing library function or adding an extra argument are quite common.&lt;/p&gt;
&lt;p&gt;This is mostly fine for short snippets where it’s easy to run the code and test but the problem becomes significant when you &lt;del&gt;copy paste&lt;/del&gt; rely on AI for larger pieces of code.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Programming-less-and-reviewing-more-is-a-bad-trade&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Programming-less-and-reviewing-more-is-a-bad-trade&quot; class=&quot;heading-ref&quot;&gt;Programming less and reviewing more is a bad trade&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The crux of the matter is that &lt;mark&gt;I’m much more productive when I’m programming than when I’m reviewing code&lt;/mark&gt;.
With most current AI tools it feels like I’m reviewing code more than programming and that’s a bad trade for me to make.&lt;/p&gt;
&lt;section id=&quot;You-still-need-to-build-a-mental-model&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#You-still-need-to-build-a-mental-model&quot; class=&quot;heading-ref&quot;&gt;You still need to build a mental model&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While you’re writing code you’re continually building up your mental model but when you let an AI generate the code you still need to do the hard work of building your mental model.&lt;/p&gt;
&lt;p&gt;I don’t think writing code is the most important thing you’re doing while programming—it’s building a mental model of the system you’re building.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Theres-no-return-of-your-investment&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Theres-no-return-of-your-investment&quot; class=&quot;heading-ref&quot;&gt;There’s no return of your investment&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ever felt that it would be faster to just code something yourself than to gently guide a junior developer through a problem?
That’s how I feel like when I shepherd an AI, with the difference that teaching a junior programmer is an investment but the AI won’t learn no matter how many times you interact with it.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Wait, what about context windows?
Well, there’s no way to keep a context window spanning months or years.
The learning I’m talking about is more akin to training or tuning an LLM.&lt;/p&gt;
&lt;p&gt;Maybe your own AI developer that you’ll tune every time you interact with it will be available soon™.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Some-AI-tools-are-very-useful&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Some-AI-tools-are-very-useful&quot; class=&quot;heading-ref&quot;&gt;Some AI tools are very useful&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I need to clarify that while I’m skeptical towards the current AI hype I find some AI tools useful in various contexts.&lt;/p&gt;
&lt;p&gt;For programming I’m a heavy user of &lt;a href=&quot;https://help.kagi.com/kagi/ai/quick-answer.html&quot;&gt;Kagi’s quick answer&lt;/a&gt; functionality that uses AI to summarize the search results and gives you references so you can drill down further if you need to.
I use it many times a day to answer questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
How do you format a date in Python?
&lt;/li&gt;
&lt;li&gt;
How do you subscribe to a table change in postgres in Elixir?
&lt;/li&gt;
&lt;li&gt;
How do you open a new buffer in Neovim using Lua?
&lt;/li&gt;
&lt;li&gt;
How to order mp4 by length in Linux?
&lt;/li&gt;
&lt;li&gt;
What’s the cron syntax to execute a script every second day?
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s not bullet proof but the combination of good search results (way better than Google in my opinion) combined with AI’s summarizing ability is absolutely fantastic.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;I-must-be-missing-something&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#I-must-be-missing-something&quot; class=&quot;heading-ref&quot;&gt;I must be missing something&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AI dev tools are useful, I just haven’t seen the incredible productivity boost that some say exist.
Maybe they are working on different problems in different contexts than I am, have different standards, or just are better at utilizing them than I am?&lt;/p&gt;
&lt;p&gt;Because, surely, it would be way to simple to dismiss the productivity claims as people evaluating the tools as how useful they &lt;em&gt;may become&lt;/em&gt; instead of how useful they are &lt;em&gt;right now&lt;/em&gt;?&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://imgs.xkcd.com/comics/extrapolating.png&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://xkcd.com/605/&quot;&gt;xkcd: 605&lt;/a&gt;; ever relevant as a response to the currently hyped technology.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
</content></entry><entry><title>Writing Home Assistant automations using Genservers in Elixir</title><id>http://jonashietala.se/blog/2024/10/08/writing_home_assistant_automations_using_genservers_in_elixir/index.html</id><updated>2025-03-21T06:31:42+00:00</updated><link href="https://www.jonashietala.se/blog/2024/10/08/writing_home_assistant_automations_using_genservers_in_elixir" rel="alternate"/><published>2024-10-08T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I’ve been a fan of Home Assistant a while now;
it’s a great platform for home automation with its beginner friendly and feature rich UI,
support for &lt;em&gt;a ton&lt;/em&gt; of different devices and integrations,
and there’s a bunch of ways to create automations.&lt;/p&gt;
&lt;p&gt;But there’s no engine for writing automations in Elixir that I could find;
this post addresses this fatal weakness.&lt;/p&gt;
&lt;p&gt;Specifically, in this post I’ll go through:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
How to use Home Assistant’s Websocket API.
&lt;/li&gt;
&lt;li&gt;
An introduction to GenServers and concurrency in Elixir.
&lt;/li&gt;
&lt;li&gt;
How to use this knowledge to write and test a simple automation.
&lt;/li&gt;
&lt;/ol&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;While I’ll try to be as detailed as possible I’ve made some simplifications and I won’t provide the complete source code for everything in this post.
If you want to follow along I encourage you to fill in the blanks and make adjustments where applicable.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Why-Elixir&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-Elixir&quot; class=&quot;heading-ref&quot;&gt;Why Elixir?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ever since I started with home automation I’ve thought that it would be a great match for the concurrency model that Elixir uses.
You’ll have all sorts of automations running concurrently, reacting to different triggers, waiting for different actions, and interacting with each other; something I think Elixir excels at.&lt;/p&gt;
&lt;p&gt;Now, there are many options for writing automations for Home Assistant that already work well,
the biggest reason I wanted to use Elixir is because I &lt;em&gt;like&lt;/em&gt; it.
That Elixir happens to be a good fit for home automation is just a bonus.&lt;/p&gt;
&lt;p&gt;I’ve tried to write automations via the Home Assistant UI (meh), using YAML configuration (hated it), visual programming with &lt;a href=&quot;https://github.com/hassio-addons/addon-node-red&quot;&gt;Node-RED&lt;/a&gt; (I want real programming), and in Python using &lt;a href=&quot;https://github.com/custom-components/pyscript&quot;&gt;Pyscript&lt;/a&gt; (pretty good).
In the end I simply enjoyed writing automations in Elixir more.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;People think that home automation exists to make your life easier, but that’s just a bi-product of the true purpose of home automation: &lt;strong&gt;having fun&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Controlling-Home-Assistant-from-Elixir&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Controlling-Home-Assistant-from-Elixir&quot; class=&quot;heading-ref&quot;&gt;Controlling Home Assistant from Elixir&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The very first thing we need to solve is how do we get data from Home Assistant and how to call services (now called actions)?&lt;/p&gt;
&lt;p&gt;Home Assistant has a &lt;a href=&quot;https://developers.home-assistant.io/docs/api/websocket/&quot;&gt;websocket API&lt;/a&gt; and a &lt;a href=&quot;https://developers.home-assistant.io/docs/api/rest/&quot;&gt;REST API&lt;/a&gt; that we can use to implement our engine.
As we can get entity states and call services over the websocket there’s no need to bother with the &lt;a href=&quot;https://developers.home-assistant.io/docs/api/rest/&quot;&gt;REST API&lt;/a&gt; for our example.&lt;/p&gt;
&lt;section id=&quot;Connecting&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Connecting&quot; class=&quot;heading-ref&quot;&gt;Connecting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I used &lt;a href=&quot;https://hexdocs.pm/websockex/WebSockex.html&quot;&gt;WebSockex&lt;/a&gt; to setup the websocket connection to Home Assistant.
Here’s a tentative start that connects and receives a message:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClient&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;WebSockex&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Adjust to your Home Assitant instance
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;url&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;ws://lannisport:8123/api/websocket&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;start_link&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_args&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;WebSockex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;url&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_frame&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;text&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Jason&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;decode&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;debug&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Received:&lt;span class=&quot;constant character escape char elixir&quot;&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;inspect&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        handle_msg&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;error&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;warning&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Couldn&amp;#39;t decode message `&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;inspect&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;`:&lt;span class=&quot;constant character escape char elixir&quot;&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;inspect&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_msg&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;warning&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;Unhandled message: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;punctuation section interpolation begin elixir&quot;&gt;#{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;meta interpolation elixir&quot;&gt;&lt;span class=&quot;source elixir embedded&quot;&gt;inspect&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section interpolation end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;source elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As with all concurrent services in Elixir Websockex should be started in a supervision tree.
Under the main Application Supervisor works well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lib&amp;#x2F;haex&amp;#x2F;application.ex&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;Application&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment documentation false&quot;&gt;@moduledoc false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Application&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_type&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; _args&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    children &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClient&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Supervisor&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;children&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;strategy&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;one_for_one&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;The main purpose of the supervision tree is to provide fault tolerance by monitoring and restarting processes if they fail.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;If we run this then Home Assistant will send us a message upon connection:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[warning] Unhandled message: %{&quot;ha_version&quot; =&gt; &quot;2024.10.0&quot;, &quot;type&quot; =&gt; &quot;auth_required&quot;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means we need to authenticate using a &lt;a href=&quot;https://community.home-assistant.io/t/how-to-get-long-lived-access-token/162159/6&quot;&gt;long lived access token&lt;/a&gt;.
Reading the &lt;a href=&quot;https://developers.home-assistant.io/docs/api/websocket/&quot;&gt;websocket API&lt;/a&gt; we should respond with an 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;auth&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; message:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_msg&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;type&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;auth_required&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  token &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;fetch_env!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;haex&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;access_token&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  reply &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Jason&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;encode!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant other keywords elixir&quot;&gt;type&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;auth&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant other keywords elixir&quot;&gt;access_token&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; token
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;reply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;text&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; reply&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s prudent to fetch secrets from environment variables in &lt;code&gt;runtime.exs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;config&amp;#x2F;runtime.exs&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;config &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;haex&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;access_token&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;fetch_env!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;HA_ACCESS_TOKEN&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we get another unhandled message, telling us our auth succeeded:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[warning] Unhandled message: %{&quot;ha_version&quot; =&gt; &quot;2024.10.0&quot;, &quot;type&quot; =&gt; &quot;auth_ok&quot;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Subscribing-to-state-changes&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Subscribing-to-state-changes&quot; class=&quot;heading-ref&quot;&gt;Subscribing to state changes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After authenticating we can tell Home Assistant that we’d like to subscribe to all state changes in the system (so we can  write automations that trigger on a state change).&lt;/p&gt;
&lt;p&gt;I’m lazy so I send the subscription message when I’m handling (ignoring) the 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;auth_ok&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; message:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_msg&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;type&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;auth_ok&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  reply &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Jason&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;encode!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;id&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;type&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;subscribe_events&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;event_type&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;state_changed&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;reply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;text&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; reply&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this up we’ll get another acknowledgment that our subscribe command succeeded (matching 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;id&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt;&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[warning] Unhandled message: %{&quot;id&quot; =&gt; 1, &quot;result&quot; =&gt; nil, &quot;success&quot; =&gt; true, &quot;type&quot; =&gt; &quot;result&quot;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we start receiving state changed messages:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[warning] Unhandled message: %{&quot;event&quot; =&gt; %{&quot;context&quot; =&gt; %{&quot;id&quot; =&gt; &quot;01J9DK3CN0CEEWGCV1139HTC11&quot;, &quot;parent_id&quot; =&gt; nil, &quot;user_id&quot; =&gt; nil}, &quot;data&quot; =&gt; %{&quot;entity_id&quot; =&gt; &quot;sensor.vardagsrum_innelampor_switch_power&quot;, &quot;new_state&quot; =&gt; %{&quot;attributes&quot; =&gt; %{&quot;device_class&quot; =&gt; &quot;power&quot;, &quot;friendly_name&quot; =&gt; &quot;Vardagsrum innelampor switch Power&quot;, &quot;state_class&quot; =&gt; &quot;measurement&quot;, &quot;unit_of_measurement&quot; =&gt; &quot;W&quot;}, &quot;context&quot; =&gt; %{&quot;id&quot; =&gt; &quot;01J9DK3CN0CEEWGCV1139HTC11&quot;, &quot;parent_id&quot; =&gt; nil, &quot;user_id&quot; =&gt; nil}, &quot;entity_id&quot; =&gt; &quot;sensor.vardagsrum_innelampor_switch_power&quot;, &quot;last_changed&quot; =&gt; &quot;2024-10-05T05:40:36.640422+00:00&quot;, &quot;last_reported&quot; =&gt; &quot;2024-10-05T05:40:36.640422+00:00&quot;, &quot;last_updated&quot; =&gt; &quot;2024-10-05T05:40:36.640422+00:00&quot;, &quot;state&quot; =&gt; &quot;4.6&quot;}, &quot;old_state&quot; =&gt; %{&quot;attributes&quot; =&gt; %{&quot;device_class&quot; =&gt; &quot;power&quot;, &quot;friendly_name&quot; =&gt; &quot;Vardagsrum innelampor switch Power&quot;, &quot;state_class&quot; =&gt; &quot;measurement&quot;, &quot;unit_of_measurement&quot; =&gt; &quot;W&quot;}, &quot;context&quot; =&gt; %{&quot;id&quot; =&gt; &quot;01J9DK37CMJBDFK7M5VGYJ1CZG&quot;, &quot;parent_id&quot; =&gt; nil, &quot;user_id&quot; =&gt; nil}, &quot;entity_id&quot; =&gt; &quot;sensor.vardagsrum_innelampor_switch_power&quot;, &quot;last_changed&quot; =&gt; &quot;2024-10-05T05:40:31.252863+00:00&quot;, &quot;last_reported&quot; =&gt; &quot;2024-10-05T05:40:31.252863+00:00&quot;, &quot;last_updated&quot; =&gt; &quot;2024-10-05T05:40:31.252863+00:00&quot;, &quot;state&quot; =&gt; &quot;4.5&quot;}}, &quot;event_type&quot; =&gt; &quot;state_changed&quot;, &quot;origin&quot; =&gt; &quot;LOCAL&quot;, &quot;time_fired&quot; =&gt; &quot;2024-10-05T05:40:36.640422+00:00&quot;}, &quot;id&quot; =&gt; 1, &quot;type&quot; =&gt; &quot;event&quot;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[warning] Unhandled message: %{&quot;event&quot; =&gt; %{&quot;context&quot; =&gt; %{&quot;id&quot; =&gt; &quot;01J9DK3CQ27BWBX0R9MAP5SRM9&quot;, &quot;parent_id&quot; =&gt; nil, &quot;user_id&quot; =&gt; nil}, &quot;data&quot; =&gt; %{&quot;entity_id&quot; =&gt; &quot;sensor.dishwasher_plug_voltage&quot;, &quot;new_state&quot; =&gt; %{&quot;attributes&quot; =&gt; %{&quot;device_class&quot; =&gt; &quot;voltage&quot;, &quot;friendly_name&quot; =&gt; &quot;Dishwasher plug Voltage&quot;, &quot;state_class&quot; =&gt; &quot;measurement&quot;, &quot;unit_of_measurement&quot; =&gt; &quot;V&quot;}, &quot;context&quot; =&gt; %{&quot;id&quot; =&gt; &quot;01J9DK3CQ27BWBX0R9MAP5SRM9&quot;, &quot;parent_id&quot; =&gt; nil, &quot;user_id&quot; =&gt; nil}, &quot;entity_id&quot; =&gt; &quot;sensor.dishwasher_plug_voltage&quot;, &quot;last_changed&quot; =&gt; &quot;2024-10-05T05:40:36.706679+00:00&quot;, &quot;last_reported&quot; =&gt; &quot;2024-10-05T05:40:36.706679+00:00&quot;, &quot;last_updated&quot; =&gt; &quot;2024-10-05T05:40:36.706679+00:00&quot;, &quot;state&quot; =&gt; &quot;232.5&quot;}, &quot;old_state&quot; =&gt; %{&quot;attributes&quot; =&gt; %{&quot;device_class&quot; =&gt; &quot;voltage&quot;, &quot;friendly_name&quot; =&gt; &quot;Dishwasher plug Voltage&quot;, &quot;state_class&quot; =&gt; &quot;measurement&quot;, &quot;unit_of_measurement&quot; =&gt; &quot;V&quot;}, &quot;context&quot; =&gt; %{&quot;id&quot; =&gt; &quot;01J9DK37THDW13GTP09KXNMG0Q&quot;, &quot;parent_id&quot; =&gt; nil, &quot;user_id&quot; =&gt; nil}, &quot;entity_id&quot; =&gt; &quot;sensor.dishwasher_plug_voltage&quot;, &quot;last_changed&quot; =&gt; &quot;2024-10-05T05:40:31.697304+00:00&quot;, &quot;last_reported&quot; =&gt; &quot;2024-10-05T05:40:31.697304+00:00&quot;, &quot;last_updated&quot; =&gt; &quot;2024-10-05T05:40:31.697304+00:00&quot;, &quot;state&quot; =&gt; &quot;232.18&quot;}}, &quot;event_type&quot; =&gt; &quot;state_changed&quot;, &quot;origin&quot; =&gt; &quot;LOCAL&quot;, &quot;time_fired&quot; =&gt; &quot;2024-10-05T05:40:36.706679+00:00&quot;}, &quot;id&quot; =&gt; 1, &quot;type&quot; =&gt; &quot;event&quot;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Managing-cross-service-messages-with-PubSub&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Managing-cross-service-messages-with-PubSub&quot; class=&quot;heading-ref&quot;&gt;Managing cross-service messages with PubSub&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At this point I’d like to take a step and plan ahead a little.
We have our state changed events but how should we send them to the automations we’ll write?&lt;/p&gt;
&lt;p&gt;One option might be to let 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;WebSocketClient&lt;/span&gt;&lt;/code&gt; loop over all automations and call them directly:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_msg&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;msg &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;type&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;event&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;for&lt;/span&gt; automation &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;&amp;lt;-&lt;/span&gt; automations &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    automation&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;state_changed&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But that’s not very flexible.
We’d have to keep the &lt;code&gt;automations&lt;/code&gt; list updated and what about other services that might want to subscribe to state changes but aren’t automations?&lt;/p&gt;
&lt;p&gt;Instead I opted to use &lt;a href=&quot;https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html&quot;&gt;Phoenix.PubSub&lt;/a&gt;, a publisher/subscriber service that can broadcast messages throughout your application.&lt;/p&gt;
&lt;p&gt;First we’ll need to start an instance in our supervision tree (called 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lib&amp;#x2F;haex&amp;#x2F;application.ex&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_type&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; _args&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  children &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClient&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;Supervisor&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;children&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;strategy&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;one_for_one&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can broadcast messages to anyone who cares to listen:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;handle_msg&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;type&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;event&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;event&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator map-pair elixir&quot;&gt;=&amp;gt;&lt;/span&gt; event&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;broadcast&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;state_schanged&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;state_changed&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;     %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;       &lt;span class=&quot;constant other keywords elixir&quot;&gt;entity_id&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; event&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;entity_id&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;       &lt;span class=&quot;constant other keywords elixir&quot;&gt;new_state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; event&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;new_state&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;       &lt;span class=&quot;constant other keywords elixir&quot;&gt;old_state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; event&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;old_state&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;     &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If a service wants to receive the messages they’ll subscribe to the 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;state_changed&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; channel:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;subscribe&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;state_changed&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Calling-services&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Calling-services&quot; class=&quot;heading-ref&quot;&gt;Calling services&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There’s key component left and that’s how do call a service / execute an action?&lt;/p&gt;
&lt;p&gt;You call a service by sending this type of message over the websocket:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;&lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This message turns on a light.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;id&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;type&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;call_service&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;domain&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;light&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;service&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;turn_on&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;target&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;entity_id&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;light.j_kontor_dator_ledstrip&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;service_data&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;beige&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You’ll then receive a successful result message corresponding to the &lt;code&gt;id&lt;/code&gt; of the message.
You’re supposed to correlate the &lt;code&gt;id&lt;/code&gt;s of the messages you send and receive, but it’s not central to this post so I’ll gloss over that implementation detail.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Outline-of-a-GenServer-automation&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Outline-of-a-GenServer-automation&quot; class=&quot;heading-ref&quot;&gt;Outline of a GenServer automation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I decided to create automations as regular &lt;a href=&quot;https://hexdocs.pm/elixir/GenServer.html&quot;&gt;GenServer&lt;/a&gt;s that subscribes to triggers and then does stuff.
An automation might look like something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Automations&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;MyAutomation&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;start_link&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;subscribe&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;time&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; time&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Do something at a specific time
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you’re unfamiliar with GenServers then the gist is that a GenServer is an isolated process that receives messages and should be started in a supervision tree.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;GenServers represent different kind of “object oriented programming”,
very similar to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Actor_model&quot;&gt;Actor Model&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;In the above example we subscribe to the 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;time&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; channel and then receive a message with the &lt;code&gt;handle_info&lt;/code&gt; callback.
(The 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;time&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; message is generated from a 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;state_changed&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; message for the entity &lt;code&gt;sensor.time&lt;/code&gt; that’s updated every minute.)&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Let-there-be-light&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Let-there-be-light&quot; class=&quot;heading-ref&quot;&gt;Let there be light&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s finally time for the ultimate expression of home automation:&lt;br&gt;
controlling a light source.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Gentlemen I am now about to send a signal from this laptop through our local ISP racing down fiber-optic cable at the speed of light to San Francisco, bouncing off a satellite in geosynchronous orbit to Lisbon Portugal where the data packets will be handed off to submerge transatlantic cables terminating in Halifax Nova Scotia, and transferred across the continent via microwave relays back to our ISP and the XM receiver attached to this…&lt;/p&gt;
&lt;p&gt;Lamp.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mqp8_ROAIJY&quot;&gt;Big Bang Theory: Internet success&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;Jokes aside, controlling a light is great because it’s easy to start with (turn on/off), you’ll get to see results in the real world (the light changes color), and you can increase the complexity if you want (create a sunrise alarm, use &lt;a href=&quot;https://www.thelightingpractice.com/what-is-circadian-lighting/&quot;&gt;circadian lighting&lt;/a&gt;, flash during a fire alarm, etc).&lt;/p&gt;
&lt;section id=&quot;Time-trigger&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Time-trigger&quot; class=&quot;heading-ref&quot;&gt;Time trigger&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s ease into an automation by turning on a light on a specific time:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Automations&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;BedroomLight&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Phoenix&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This is the Home Assistant entity I want to control.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;light.jonas_bedroom_lamp&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;start_link&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;subscribe&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;time&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; time&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Note that time only ticks every minute so seconds will always be zero.
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:00:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;yellow&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Wake-up-lighting&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Wake-up-lighting&quot; class=&quot;heading-ref&quot;&gt;Wake-up lighting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;That was easy.
Let’s try something bit more interesting: a wake-up sequence.&lt;/p&gt;
&lt;p&gt;Specifically I’d like to gradually change the brightness and color of the light from a dim red to a bright, white light.&lt;/p&gt;
&lt;p&gt;We could hardcode it with something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; time&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;keyword control elixir&quot;&gt;cond&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:00:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;red&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:10:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;70&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;orange&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:20:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;gold&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:30:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;kelvin&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;2700&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;constant language elixir&quot;&gt;nil&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But that’s not flexible if we for example want the start time to be configurable via the UI in the future.
While refactoring it let’s try to implement the transitions using a message passing approach:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;0&quot;&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;1&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; time&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;2&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:00:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot;3&quot;&gt;    send&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot;4&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;light_state&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;5&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;6&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;7&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;8&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At line 3 we’re using &lt;code&gt;send()&lt;/code&gt; to send the message 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;/code&gt; to ourselves and at line 4 we’re tracking inserting 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;light_state&lt;/span&gt;&lt;/code&gt; as 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;, to let the GenServer keep track of what transition we should perform.&lt;/p&gt;
&lt;p&gt;This message is again handled by &lt;code&gt;handle_info&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 0&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;light_state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 1&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; set_sunrise_light&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 2&quot;&gt;    &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;done&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 3&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; We&amp;#39;ve reached our last transition.
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 4&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;day&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 5&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 6&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;next&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 7&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; We still have transitions left to handle,
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; send another :transition_sunrise message after 10 minutes,
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; repeating the loop.
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;10&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send_after&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;11&quot;&gt;      &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;light_state&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;12&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;13&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The function &lt;code&gt;set_sunrise_light&lt;/code&gt; sets the light depending on 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; sunrise_state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; and returns 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;done&lt;/span&gt;&lt;/code&gt; when we’ve set the last transition.
Pay attention to line 10 where we send another 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;/code&gt; message but with a delay, continuing the recursion until we’ve set handled all transitions.&lt;/p&gt;
&lt;p&gt;I’m not thrilled about the implementation of &lt;code&gt;set_sunrise_light&lt;/code&gt; but here it is:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;set_sunrise_light&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;%&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;light_state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; sunrise_state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   transitions &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;red&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;70&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;orange&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;gold&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;kelvin&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;2700&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;     &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Transform the list into a map with index =&amp;gt; transition.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;     &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Yes, it&amp;#39;s a shoddy imitation of an array.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;     &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;with_index&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;new&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;val&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; index&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;index&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; val&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   last_state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;transitions&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;light_opts&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; next_transition&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; sunrise_state &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;&amp;gt;=&lt;/span&gt; last_state &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;transitions&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;last_state&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;done&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;transitions&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;sunrise_state&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;next&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; sunrise_state &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; light_opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   next_transition
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Abort-the-wake-up-sequence&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Abort-the-wake-up-sequence&quot; class=&quot;heading-ref&quot;&gt;Abort the wake-up sequence&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’d like to add the ability to abort the sunrise alarm by turning off the lamp.
It’s fairly straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Subscribe to a state change:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;subscribe&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;PubSub&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;state:&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator binary-concatenation elixir&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(I use a simplified message instead of the raw 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;state_changed&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; message we’ve seen before.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change the state if we’re in a sunrise:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;off&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;state&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;day&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We still have a 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;/code&gt; message that will arrive later but the fallback &lt;code&gt;handle_info&lt;/code&gt; will ignore it.
If we’ll implement a snooze or restart for our sunrise this may become a problem.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Refactoring-into-another-GenServer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Refactoring-into-another-GenServer&quot; class=&quot;heading-ref&quot;&gt;Refactoring into another GenServer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What we’ve done so far works but the structure isn’t ideal.
The leftover 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;/code&gt; message bothers me and what if we want to implement another light transition,
either for a bedtime routine or for another light?
Then we’d have to re-implement a large portion of the automation, which isn’t my idea of fun.&lt;/p&gt;
&lt;p&gt;We can break out the code into another GenServer, let’s call it 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;LightTransition&lt;/span&gt;&lt;/code&gt;,
and we can let it keep track of the transitions and lets us focus on the more interesting parts of automation writing.&lt;/p&gt;
&lt;p&gt;This lets us start a sunrise with something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 0&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; time &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:00:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 1&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; transition_pid&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot; 2&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;LightTransition&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 3&quot;&gt;      &lt;span class=&quot;constant other keywords elixir&quot;&gt;entity_id&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 4&quot;&gt;      &lt;span class=&quot;constant other keywords elixir&quot;&gt;transitions&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 5&quot;&gt;        &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;red&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 6&quot;&gt;        &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;70&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;orange&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 7&quot;&gt;        &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;gold&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 8&quot;&gt;        &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;kelvin&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;2700&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 9&quot;&gt;      &lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;10&quot;&gt;    &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;11&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;12&quot;&gt;  state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;13&quot;&gt;    state
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;14&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;light_state&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot;15&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; transition_pid&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;16&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;17&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At line 2 we start our transition using &lt;code&gt;start_link&lt;/code&gt;, foregoing the supervision tree as it doesn’t make sense to have the transition without the automation.
We keep track of the service process id at line 15, which we can use to stop the transition if needed:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;stop&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;transition&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;LightTransition&lt;/span&gt;&lt;/code&gt; itself is fairly straightforward when we don’t have to keep track of the transition state:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;.&lt;span class=&quot;entity name class elixir&quot;&gt;LightTransition&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;start_link&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    send&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;new&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_info&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;case&lt;/span&gt; state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;transitions &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;stop&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;normal&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;light_opts &lt;span class=&quot;keyword operator other elixir&quot;&gt;|&lt;/span&gt; rest&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;entity_id&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; light_opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        timer &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send_after&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; light_opts&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;transition&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;noreply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;merge&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;transitions&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; rest&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;timer&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; timer&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;last&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; light_opts&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this in place we can support pause and resume by using 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;read_timer&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/code&gt; and 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;cancel_timer&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;impl&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_call&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;pause&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;timer&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; timer&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  time_left &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;read_timer&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;cancel_timer&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    state
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time_left&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; time_left&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;timer&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;reply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;handle_call&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;resume&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;time_left&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; time_left&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;entity_id&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;last&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  timer &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send_after&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; time_left&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  state &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    state
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;timer&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; timer&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator pipe elixir&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;delete&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time_left&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;reply&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I think things turned out pretty well in the end.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;State-machines-are-great&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#State-machines-are-great&quot; class=&quot;heading-ref&quot;&gt;State machines are great&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So far we only have a sunrise alarm, but it’s easy to imagine more features that our humble lamp could support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Snooze the wake-up light (using the above pause/resume functionality).
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.thelightingpractice.com/what-is-circadian-lighting/&quot;&gt;Circadian lighting&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
A bedtime transition, similar to a reverse wake-up light except it shouldn’t force the light on.
&lt;/li&gt;
&lt;li&gt;
A “max power mode” that sets the light to max brightness, triggered by toggling &lt;code&gt;on/off&lt;/code&gt; quickly. Should only end when you turn off the light.
&lt;/li&gt;
&lt;li&gt;
The all-important “sexy time” mode.
&lt;/li&gt;
&lt;li&gt;
If a fire alarm goes off, flash the light in an aggressive way. Should of course override every other mode.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While you could implement them all as separate automations, the more you add the harder it gets to keep them from interfering with each other.
You wouldn’t want your sexy time to be interrupted would you?&lt;/p&gt;
&lt;p&gt;An alternative is to use a state machine to track the different states, making the state transitions more explicit.
Our automation is already a simple state machine and it’s fairly easy to add more states and more functionality to it.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Automation-testing&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Automation-testing&quot; class=&quot;heading-ref&quot;&gt;Automation testing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An automation is just an Elixir GenServer, so the same strategies to test a GenServer applies here too.
I’ll start with the test I want to write, and we’ll work backwards to make it work:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;test &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;trigger sunrise&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;server&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; server&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Start the sunrise by sending a time message to the automation.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  send&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;server&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:00:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Assert that we&amp;#39;ll eventually receive the sunrise transitions.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  assert eventually&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;           &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;kelvin&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;2700&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;gold&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;70&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;orange&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;red&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_name&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;red&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;           &lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             &lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClientCollector&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;get_messages&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;               &lt;span class=&quot;constant other keywords elixir&quot;&gt;get_service_data&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             &lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;section id=&quot;An-isolated-GenServer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#An-isolated-GenServer&quot; class=&quot;heading-ref&quot;&gt;An isolated GenServer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first thing we’ll need to do is to start the GenServer so we can start interacting with it.
We don’t need a supervision tree so we can start it directly and send it to the test:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;setup _opts &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; server&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;BedroomLight&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;server&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; server&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;test &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;trigger sunrise alarm&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;server&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; server&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I like to test against isolated GenServers as it allows parallel testing and it reduces the risk of contamination from other parts of the application.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Alter-the-code-to-be-able-to-test&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Alter-the-code-to-be-able-to-test&quot; class=&quot;heading-ref&quot;&gt;Alter the code to be able to test?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If we run this test we’ll notice that the automation will only output the first sunrise transition.
What gives?&lt;/p&gt;
&lt;p&gt;Remember this line?&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send_after&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It says that we’ll continue the sunrise transition after &lt;em&gt;10 minutes&lt;/em&gt;.
Nobody wants to wait that long for a test to finish…&lt;/p&gt;
&lt;p&gt;To get around this I added an option to the automation so that we can override the delay to 1 millisecond during the test:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;setup opts &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  opts &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;put_new&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_time&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ok&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; server&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;BoysRoofLight&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;start_link&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;server&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; server&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;&lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; And in the automation:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;transition_time &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; state&lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_time&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator other elixir&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic elixir&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1000&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send_after&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;transition_sunrise&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; transition_time&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don’t like modifying code just to make tests work but in this case I think it’s a reasonable workaround.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-eventually-helper&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#The-eventually-helper&quot; class=&quot;heading-ref&quot;&gt;The eventually helper&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I want to touch on the &lt;code&gt;eventually&lt;/code&gt; helper that I think is super useful when testing processes in Elixir.
It comes in handy whenever I want to wait for a message to be delivered or wait for a process to reach a certain state.&lt;/p&gt;
&lt;p&gt;Here it is:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;eventually&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;func&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; timeout &lt;span class=&quot;keyword operator other elixir&quot;&gt;\\&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1_000&lt;/span&gt;) &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Use Task to be able to timeout the execution.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  task &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;async&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt; _eventually&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;func&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;await&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; timeout&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;entity name function private elixir&quot;&gt;_eventually&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;func&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; func&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;      &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Return true so we can use it in an `assert` statement.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;sleep&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      _eventually&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;func&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;rescue&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Safe up so we don&amp;#39;t have to bother with proper matches etc
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;    &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; inside the predicate function.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    _ &lt;span class=&quot;keyword operator arrow elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;sleep&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      _eventually&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;func&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Careful use of checkpoints in our tests, where we wait for a state to be fulfilled, is much preferable over sprinkling 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;sleep&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/code&gt; in our tests, hoping that the race conditions will go away.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Capturing-sent-websocket-messages&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Capturing-sent-websocket-messages&quot; class=&quot;heading-ref&quot;&gt;Capturing sent websocket messages&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The last thing we need is to capture outgoing websocket messages.
In fact we also need to block the websocket connection because as it is now the full application will run when we run then tests, including connecting to our Home Assistant instance and start receiving state changed events.&lt;/p&gt;
&lt;p&gt;We can do this by replacing the websocket client during tests.
The application config is a good place for these settings:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;config&amp;#x2F;config.exs&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;config &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;haex&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;ws_client&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Haex&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClient&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;config&amp;#x2F;test.exs&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;config &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;haex&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;ws_client&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClientCollector&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then when we send a message we delegate to the proper client:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  ws_client&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;send&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;ws_client&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;entity name class elixir&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;fetch_env!&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;haex&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;ws_client&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClientCollector&lt;/span&gt;&lt;/code&gt; does is collect sent messages by process id and is able to return a list of them:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClientCollector&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;call&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;send&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;get_messages&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;opts &lt;span class=&quot;keyword operator other elixir&quot;&gt;\\&lt;/span&gt; &lt;span class=&quot;punctuation section array elixir&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section array elixir&quot;&gt;]&lt;/span&gt;) &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;GenServer&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;call&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language elixir&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;get_messages&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Skipped the implementation ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this our test for the sunrise alarm should pass!&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Beware that if we run tests in parallel the collector will receive messages from all tests and we need a way to separate them.&lt;/p&gt;
&lt;p&gt;If we use unique &lt;code&gt;entity_ids&lt;/code&gt; for all test modules we could filter on that (even with 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;ExUnit&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Case&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;async&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant language elixir&quot;&gt;true&lt;/span&gt;&lt;/code&gt; tests in a module aren’t run concurrently, but remember to clear messages between tests).&lt;/p&gt;
&lt;p&gt;Or we could do what &lt;a href=&quot;https://hexdocs.pm/mox/Mox.html&quot;&gt;Mox&lt;/a&gt; does and separate results by calling process id.
This is the most robust but it’s a more cumbersome to implement as we’re using nested processes (the child process 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;LightTransition&lt;/span&gt;&lt;/code&gt; GenServer will call 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;/code&gt;, so we need to &lt;a href=&quot;https://hexdocs.pm/mox/Mox.html#module-explicit-allowances&quot;&gt;explicitly allow&lt;/a&gt; it).&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Beware-of-race-conditions&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Beware-of-race-conditions&quot; class=&quot;heading-ref&quot;&gt;Beware of race conditions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tests in an asynchronous and concurrent system—where messages don’t arrive immediately and where services interact with each other—can be very annoying to deal with as it’s easy to introduce race conditions, where a test &lt;em&gt;sometimes&lt;/em&gt; fail.&lt;/p&gt;
&lt;p&gt;Consider this test where we’ll test that the sunrise is aborted if the light is turned off in the middle:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 0&quot;&gt;&lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;tag&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;transition_time&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;10&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 1&quot;&gt;test &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;turn off light after sunrise alarm has begun halts it&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; %&lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other keywords elixir&quot;&gt;server&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; server&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 2&quot;&gt;  send&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;server&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;storage type string elixir&quot;&gt;~T&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted other literal upper elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;[&lt;/span&gt;06:00:00&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 3&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 4&quot;&gt;  assert eventually&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 5&quot;&gt;           &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;sunrise&lt;/span&gt; &lt;span class=&quot;keyword operator assignment elixir&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;BedroomLight&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;get_state&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;server&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 6&quot;&gt;         &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 7&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 8&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Should stop the sunrise
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 9&quot;&gt;&lt;/span&gt;  send&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;server&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence tuple elixir&quot;&gt;&lt;span class=&quot;punctuation section sequence begin elixir&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable other module elixir&quot;&gt;&lt;span class=&quot;keyword operator definition constant elixir&quot;&gt;@&lt;/span&gt;entity&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;off&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end elixir&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;10&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;11&quot;&gt;  assert eventually&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;12&quot;&gt;           &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;day&lt;/span&gt; &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;BedroomLight&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;get_state&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;server&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;13&quot;&gt;         &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;14&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;15&quot;&gt;  assert &lt;span class=&quot;entity name class elixir&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity name class elixir&quot;&gt;WebsocketClientCollector&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;get_messages&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;server&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;16&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Even though it appears we’re avoiding race conditions by waiting for the automation to change its internal state at line 4 and 11, this test may still fail on occasion.&lt;/p&gt;
&lt;p&gt;The issue is that on the last line we’re testing that we only received a single sunrise transition.
But we set a transition time of &lt;code&gt;10&lt;/code&gt; milliseconds on line 0, and &lt;em&gt;sometimes&lt;/em&gt; the messages arrive in such a way that the automation manages to transition twice.&lt;/p&gt;
&lt;p&gt;To add some leeway in our test we might try to change the condition to &lt;code&gt;&amp;lt; 4&lt;/code&gt; and to increase the transition time…&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Theoretically the test could still fail even with our precautions.
Testing timeouts reliably is hard.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Whats-next&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Whats-next&quot; class=&quot;heading-ref&quot;&gt;What’s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We already have a working home automation engine that can be used as-is to control our home.
But there are a couple of features that are missing and would enhance the system, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Cron style support.&lt;/p&gt;
&lt;p&gt;We can add cron-like scheduling to our automations using libraries such as &lt;a href=&quot;https://hexdocs.pm/quantum/readme.html&quot;&gt;Quantum&lt;/a&gt; or &lt;a href=&quot;https://github.com/oban-bg/oban&quot;&gt;Oban&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A simpler API for simpler automations.&lt;/p&gt;
&lt;p&gt;While GenServers are great in many ways they’re a bit verbose for simple automations.
I took inspiration from &lt;a href=&quot;https://appdaemon.readthedocs.io/en/latest/AD_API_REFERENCE.html#appdaemon.entity.Entity.listen_state&quot;&gt;AppDaemon’s &lt;code&gt;listen_state&lt;/code&gt;&lt;/a&gt; for a simpler API:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;&lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; This automation turns on a ledstrip behind my monitors when the plug power
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;&lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; is above 180, which happens when I turn on my three monitors.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;listen_state&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;sensor.winterfell_plug_power&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;keyword operator other elixir&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;Light&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;turn_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;light.j_kontor_dator_ledstrip&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;color_temp&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;220&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other keywords elixir&quot;&gt;brightness_pct&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;punctuation separator object elixir&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant other keywords elixir&quot;&gt;gt&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;180&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;listen_state&lt;/code&gt; is implemented by—you guessed it—a GenServer.
&lt;code&gt;listen_state&lt;/code&gt; registers a trigger callback together with some trigger conditions within the GenServer, then the server calls the callbacks whenever the conditions are met.
This way we don’t need to mess with the internals of a GenServer and can use a declarative approach to create simpler automations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Querying entity states.&lt;/p&gt;
&lt;p&gt;Sometimes we want to only execute an automation if an entity has a specific value, for example:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; is_on&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;input_boolean.doorbell_sound_enabled&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign elixir&quot;&gt;  &lt;span class=&quot;punctuation definition comment elixir&quot;&gt;#&lt;/span&gt; Trigger doorbell
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I support this with the &lt;code&gt;States&lt;/code&gt; GenServer that holds the state of every entity in Home Assistant.
At startup it &lt;a href=&quot;https://developers.home-assistant.io/docs/api/websocket/#fetching-states&quot;&gt;fetches all states&lt;/a&gt; and uses the state changed event &lt;a href=&quot;#Subscribing-to-state-changes&quot;&gt;we’ve seen before&lt;/a&gt; to keep it in sync.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate automation entities.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/toggle_automations.png&quot;&gt;
&lt;figcaption&gt;Home Assistant dashboard to enable/disable automations.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I want to be able to enable and disable the automations in the system.
I’ve been manually creating &lt;code&gt;input_boolean.&amp;lt;automation&amp;gt;_enabled&lt;/code&gt; entities, but our automation engine could create these manually.
We could keep track of when the automation was last triggered and display the internal state of automations for debugging purposes.&lt;/p&gt;
&lt;p&gt;To set states (and create entities) we need to use the &lt;a href=&quot;https://developers.home-assistant.io/docs/api/rest/&quot;&gt;REST API&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There’s probably a bunch of things I haven’t yet realized that I need, but at the moment I’m really happy with writing my home automations in Elixir.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Trying and returning the Eight Sleep Pod 4</title><id>http://jonashietala.se/blog/2024/10/05/trying_and_returning_the_eight_sleep_pod_4/index.html</id><updated>2025-05-16T10:52:05+00:00</updated><link href="https://www.jonashietala.se/blog/2024/10/05/trying_and_returning_the_eight_sleep_pod_4" rel="alternate"/><published>2024-10-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I recently bought the &lt;a href=&quot;https://www.eightsleep.com/se/product/pod-cover/&quot;&gt;Eight Sleep Pod 4&lt;/a&gt;—a smart mattress cover that tracks your heart rate, HRV, snoring, and cools or warms the mattress during the night.
There’s a lot to like about the mattress but in the end I opted to return it.&lt;/p&gt;
&lt;p&gt;This post describes my experience with the Pod 4.&lt;/p&gt;
&lt;section id=&quot;Sleep-is-important-enough-to-offset-the-steep-price&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Sleep-is-important-enough-to-offset-the-steep-price&quot; class=&quot;heading-ref&quot;&gt;Sleep is important enough to offset the steep price&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.eightsleep.com/se/&quot;&gt;Eight Sleep&lt;/a&gt; mattress is really expensive but that’s not all—it’s a mattress with &lt;strong&gt;a subscription&lt;/strong&gt;!
I hated it when &lt;a href=&quot;https://ouraring.com/&quot;&gt;Oura&lt;/a&gt; introduced a subscription for their ring, and I hate the world that led us to a &lt;em&gt;mattress&lt;/em&gt; with a subscription.&lt;/p&gt;
&lt;p&gt;So why bother with the ridiculous pricing?&lt;/p&gt;
&lt;p&gt;Because &lt;mark&gt;sleep is important&lt;/mark&gt;.&lt;/p&gt;
&lt;p&gt;What would 60 or even 30 minutes of extra sleep per day be worth?
Or maybe the same amount of sleep but better?
For me, as a parent of young kids that wakes up way too early, the answer is that it would be worth &lt;strong&gt;a lot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That’s why I was able to look past the price and give Eight Sleep a chance.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;My-experience-with-the-smart-mattress&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#My-experience-with-the-smart-mattress&quot; class=&quot;heading-ref&quot;&gt;My experience with the smart mattress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a bunch of things I like about the mattress and a bunch of things I didn’t like about it.
The cons outweigh the pros for me but not by much; if my circumstances were a little different I might have kept it.&lt;/p&gt;
&lt;section id=&quot;Pros&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Pros&quot; class=&quot;heading-ref&quot;&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Sleep generally improved.&lt;/p&gt;
&lt;p&gt;I didn’t get the promised +30 minutes of extra sleep but anecdotally it was a positive change.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The mattress could get very hot and cold.&lt;/p&gt;
&lt;p&gt;I was worried that the mattress wouldn’t be able to get cold enough but it was able to go &lt;em&gt;really&lt;/em&gt; cool.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tap control on the side works very well.&lt;/p&gt;
&lt;p&gt;It was very easy to tap the side of the bed to increase or decrease the temperature (at least for me, the bed is flush to the other wall).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Separate sections of the bed is excellent.&lt;/p&gt;
&lt;p&gt;Although our kids slept with us the two sections worked well for us.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It’s a cool gadget—I like gadgets.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Cons&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Cons&quot; class=&quot;heading-ref&quot;&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;There’s no way to connect it to Home Assistant.&lt;/p&gt;
&lt;p&gt;I like home automation and I’ll freely admit that if I could’ve connected the bed to Home Assistant I would’ve kept it, everything else be damned.&lt;/p&gt;
&lt;p&gt;Using it as a presence sensor and being able to track the temperature of the bed and create my own automations would be glorious.&lt;/p&gt;
&lt;p&gt;But alas, Eight Sleep keeps all the data to themselves and want you to pay for the expensive subscription for the &lt;em&gt;privilege&lt;/em&gt; of controlling your own mattress.&lt;/p&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update &lt;span class=&quot;date&quot;&gt;2024-10-06&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;An integration for Home Assistant &lt;a href=&quot;https://github.com/lukas-clarke/eight_sleep&quot;&gt;actually exists&lt;/a&gt;.
I feel very silly now.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I sleep parts or even whole nights in my kids’ bed.&lt;/p&gt;
&lt;p&gt;To benefit from this kind of mattress you need to sleep on it, which I didn’t always do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The app is a black box.&lt;/p&gt;
&lt;p&gt;I was severely disappointed in the app as it doesn’t provide any insight into what the Autopilot is doing, making you question if it does anything at all or if it’s just empty AI marketing.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;There’s no history of the temperature adjustments during the night.&lt;/p&gt;
&lt;p&gt;You can’t look back at the night and see your own or the Autopilot’s temperature adjustments.
My own adjustments aren’t even saved so the temperature settings for the next night is a guessing game.&lt;/p&gt;
&lt;p&gt;Eight Sleep claims that Autopilot is making adjustments but for all I know it’s not doing anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The “Autopilot has reduced your X by Y%” messages feels made up.&lt;/p&gt;
&lt;p&gt;I didn’t have the Pod 4 Ultra that can elevate the bed, so how can the Autopilot reduce my snoring during the night?
Sometimes I didn’t sleep the whole night in the bed yet Autopilot claims it improved my deep sleep with 20%?&lt;/p&gt;
&lt;p&gt;I’ll give them the benefit of the doubt and say it’s probably bad statistics rather than regular old bullshit… But how can you tell?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Most importantly&lt;/strong&gt; it did not achieve the partner approval.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Using-the-free-30-day-return&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Using-the-free-30-day-return&quot; class=&quot;heading-ref&quot;&gt;Using the free 30 day return&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I gave it a shot but after a few weeks I decided to use the generous free 30 day return to send back the pod and get a refund (you throw away the mattress).&lt;/p&gt;
&lt;p&gt;It wasn’t the smoothest ride but the customer service did a decent enough job.
I had lots of trouble with the pickup, although that was probably an issue with the shipping company rather than Eight Sleep:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
At first, they didn’t show up.
&lt;/li&gt;
&lt;li&gt;
The next time I didn’t get a label I could print, so they couldn’t take the package.
&lt;/li&gt;
&lt;li&gt;
Then they again didn’t show up.
&lt;/li&gt;
&lt;li&gt;
Finally, we tried another shipping company and Eight Sleep sent the label to me directly, then they picked it up.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I work from home so it wasn’t that big of a deal, although it was a bit stressful.&lt;/p&gt;
&lt;p&gt;Still, the free return is great and it might be the biggest reason to try Eight Sleep.
In the future, when the kids get older and if someone reverse engineers the next generation of the Pod to connect it to Home Assistant, I might give it a try again.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Why I still blog after 15 years</title><id>http://jonashietala.se/blog/2024/09/25/why_i_still_blog_after_15_years/index.html</id><updated>2025-05-02T13:37:35+00:00</updated><link href="https://www.jonashietala.se/blog/2024/09/25/why_i_still_blog_after_15_years" rel="alternate"/><published>2024-09-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;Time flies when you’re having fun.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;Before you know it, your little babies have started school, you celebrate the &lt;em&gt;30th anniversary&lt;/em&gt; of Jurassic Park, and that little blog you started have now been going for 15 years.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;15 years&lt;/em&gt; is a long time; longer than I’ve been waiting for &lt;em&gt;Winds of Winter&lt;/em&gt;, and that wait has felt like an eternity.
How did I—who frequently abandon projects for the next shiny thing—manage to continue this blog for so long?&lt;/p&gt;
&lt;p&gt;I’m as surprised as anyone but I’ve tried to make a retrospective of how this may have happened.&lt;/p&gt;
&lt;section id=&quot;Why-I-started-the-blog&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-I-started-the-blog&quot; class=&quot;heading-ref&quot;&gt;Why I started the blog&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I started this blog because I wanted to create a bunch of &lt;a href=&quot;/projects/#games&quot;&gt;fast game prototypes&lt;/a&gt; and I wanted somewhere I could write about my plans and, ultimately, the games.&lt;/p&gt;
&lt;p&gt;You see, I was a budding programmer and I wanted to learn how to program by making a game.
Not a simple game like &lt;em&gt;Tetris&lt;/em&gt;—that would be way too sensible—no, I wanted to make a big RTS game, like &lt;a href=&quot;https://en.wikipedia.org/wiki/StarCraft&quot;&gt;StarCraft&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/Supreme_Commander_(video_game)&quot;&gt;Supreme Commander&lt;/a&gt;.
And to do that you needed a &lt;strong&gt;game engine&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So I got stuck developing my engine with truly groundbreaking features such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
A menu with keyboard &lt;em&gt;and&lt;/em&gt; mouse support.
&lt;/li&gt;
&lt;li&gt;
A console you could bring up with &lt;code&gt;F2&lt;/code&gt; where you could update variables (such as unit speed) without having to recompile.
&lt;/li&gt;
&lt;li&gt;
You could select units with proper &lt;code&gt;Ctrl&lt;/code&gt;, &lt;code&gt;Shift&lt;/code&gt;, and right click behavior.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;… But, embarrassingly, I didn’t have anything even resembling a game, and with the development speed I had I doubt I’d be finished to this day.&lt;/p&gt;
&lt;p&gt;I’d gotten stuck in the &lt;strong&gt;Game Engine Trap&lt;/strong&gt;, and I hated it.&lt;/p&gt;
&lt;p&gt;Then I found &lt;em&gt;The Experimental Gameplay Project&lt;/em&gt; (of &lt;a href=&quot;https://store.steampowered.com/app/22000/World_of_Goo/&quot;&gt;World of Goo&lt;/a&gt; fame) that promoted the idea that you should be able to create a game prototype in just 7 days.
That sounded like the perfect cure against the &lt;strong&gt;Game Engine Trap&lt;/strong&gt;, so I created this blog to document my progress.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-Ive-continued-to-blog&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-Ive-continued-to-blog&quot; class=&quot;heading-ref&quot;&gt;Why I’ve continued to blog&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the blog fulfilled it’s initial purpose as I developed around a dozen &lt;a href=&quot;/projects/#games&quot;&gt;game prototypes&lt;/a&gt; that got me out of the &lt;strong&gt;Game Engine Trap&lt;/strong&gt; (and that gave me a small “game engine” library at the end), I soon started write about other things.&lt;/p&gt;
&lt;p&gt;There are a number of reasons I continued to blog:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I enjoy writing.&lt;/p&gt;
&lt;p&gt;I realize now that the biggest reason I blog is that I enjoy the writing process.
I can’t put my finger on why, I just generally &lt;em&gt;like&lt;/em&gt; it.&lt;/p&gt;
&lt;p&gt;This isn’t always true though and I’ve had years where I’ve barely written anything at all (&lt;a href=&quot;/blog/2022&quot;&gt;2022&lt;/a&gt; for example).
Sometimes I’ve had to force myself to write something.&lt;/p&gt;
&lt;p&gt;I guess the motivation ebbs and flows sometimes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Writing helps me think more clearly and helps me flesh out ideas.&lt;/p&gt;
&lt;p&gt;The act of writing something down helps me find errors in my thinking and helps me consider different viewpoints.
Rewriting the text you’ve written has a similar benefit to refactoring your code; your thoughts will be more polished afterwards.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Publishing something forces me to do better.&lt;/p&gt;
&lt;p&gt;If I’m going to put something out there I’m going to re-read and rework my text/code/ideas more than if I had kept it for myself.
(Even if nobody will read your posts, the mere act of putting something out there has this effect I think.)&lt;/p&gt;
&lt;p&gt;For example, &lt;a href=&quot;/series/t-34/&quot;&gt;my custom keyboard layout&lt;/a&gt; wouldn’t have been nearly as well-developed if I hadn’t published it for everyone to see.&lt;/p&gt;
&lt;p&gt;Being more thoughtful about how I write is something I’ve become more cognizant of as the years have gone by.
My first posts where little more than a stream of thoughts, while the larger posts I gravitate towards today have gone through multiple revisions and rewrites before I publish them.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;At any time I have several drafts that I’m writing on, but many of them never gets published.
Sometimes I lose interest, and other times I see that the post won’t become the polished masterpiece (or at least, not a pile of dung), so I abandon it.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The blog is a place to document my personal projects.&lt;/p&gt;
&lt;p&gt;Over the years I’ve done &lt;a href=&quot;/projects&quot;&gt;other projects&lt;/a&gt;, such as &lt;a href=&quot;/series/voron_trident/&quot;&gt;built a 3D printer&lt;/a&gt; and &lt;a href=&quot;/series/making-cryptobook&quot;&gt;wrote a book&lt;/a&gt;.
It’s nice to have a place where I can write about them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Looking at a log of things I’ve done makes me feel better.&lt;/p&gt;
&lt;p&gt;I’ve been doing a small &lt;a href=&quot;/blog/tags/yearly_review&quot;&gt;yearly review&lt;/a&gt; every year where I try to list the highlights of the past year.
It’s been super helpful for me as it helps counteract the &lt;a href=&quot;/blog/2023/03/14/battling_burnout&quot;&gt;depressing feeling&lt;/a&gt; that nothing has happened and that I haven’t done anything.&lt;/p&gt;
&lt;p&gt;Doing a yearly review of some sort is a practice I highly recommend everyone to try, and of course you don’t have to publish it for everyone to see.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I enjoy developing the blog as a project that exclusively solves my problems.&lt;/p&gt;
&lt;p&gt;Programming is my biggest hobby and I can’t see myself ever stopping.
The blog is a great project as it’s something that exists only for me so I can rewrite, refactor, and add whatever silly features I want and I only have myself to answer to.
It’s a nice feeling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blogging helps me become a better writer, which in turns helps me become a better developer.&lt;/p&gt;
&lt;p&gt;I think communicating well is an important and underrated part of being an effective software developer.
Writing well is a skill that can be developed by practice, and maintaining a blog is a pretty good way to practice I’d say.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;No, dumping a stream of thought into ChatGPT isn’t good enough.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;section id=&quot;My-motivations-arent-dependent-on-external-feedback&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#My-motivations-arent-dependent-on-external-feedback&quot; class=&quot;heading-ref&quot;&gt;My motivations aren’t dependent on external feedback&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It’s important to point out that it’s not external feedback that has kept me going all these years.
Yes, of course, it’s nice to get the occasional email with compliments, but that’s just a bonus.&lt;/p&gt;
&lt;p&gt;&lt;mark&gt;I keep this blog for me to write, not necessarily for others to read.&lt;/mark&gt;&lt;/p&gt;
&lt;p&gt;Many of these kinds of retrospectives contain graphs of views over time or the most popular posts; but I’m not showing it to you because I can’t—I don’t keep any statistics whatsoever.&lt;/p&gt;
&lt;p&gt;I don’t really care—and I don’t want to care—about how many readers I have or what posts are and aren’t popular.
I worry that if I add statistics to the blog it’ll change from an activity I perform for the activity’s sake, to an exercise in hunting clicks where I write for others instead of for myself.&lt;/p&gt;
&lt;p&gt;If I were chasing views I would certainly not have continued to blog for as long as I have, and I’d have missed out on the &lt;a href=&quot;#Why-Ive-continued-to-blog&quot;&gt;many benefits&lt;/a&gt; I’ve gotten from the blog.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Evolution-of-the-tech-stack&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Evolution-of-the-tech-stack&quot; class=&quot;heading-ref&quot;&gt;Evolution of the tech stack&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the reasons I’ve been blogging so long is that I’ve been able to play around with the tech stack of the blog.
I’ve changed the tech stack a number of times; from choosing languages I wanted to learn, to a boring setup that “just works”, and back again.&lt;/p&gt;
&lt;div class=&quot;timeline blog-tech-stack&quot;&gt;&lt;div class=&quot;events&quot;&gt;
&lt;div class=&quot;event kohana&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;~ 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I started out with PHP using the &lt;a href=&quot;https://kohanaframework.org/&quot;&gt;Kohana Framework&lt;/a&gt; and I still have fond memories of their excellent documentation.
Although I had figured out how to create a website, it never graduated to a real blog.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event mojolicious&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;Early 2009&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Then I moved on to rewrite the site in Perl using &lt;a href=&quot;https://www.mojolicious.org/&quot;&gt;Mojolicious&lt;/a&gt;.
I’m not sure my efforts ever resulted in anything tangible but I remember if was fun to play around with.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event jekyll&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;July 2009&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I stumbled upon the idea of using a static site for my blog and therefore abandoned Perl for &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, a popular static site generator at that time.&lt;/p&gt;
&lt;p&gt;I believe it was a smart choice because it helped me &lt;a href=&quot;/blog/2009/07/21/the_first_worst_post&quot;&gt;start writing&lt;/a&gt;, instead of jerking around with cool tech.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event hakyll&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;~ July 2013&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Eventually, I grew tired of the boring backend that just got the job done and in my quest to learn Haskell I replaced the generator with &lt;a href=&quot;https://jaspervdj.be/hakyll/&quot;&gt;Hakyll&lt;/a&gt;, another static site generator with a pretty neat DSL.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event git&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;July 2013&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;The earliest Git commit on record.
I’m fairly sure I used Git before this point&lt;br&gt;
(I abandoned SVN for my games in 2009).&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event hakyll-space&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2013–2022&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Sadly, I never truly graduated from the “throw shit at the wall until it sticks” stage of my Haskell journey, which is why I barely added any features to the blog for many years.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event rust&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2022&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Having outgrown existing solutions I decided to &lt;a href=&quot;/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit&quot;&gt;join the Rewrite in Rust club&lt;/a&gt; (or is it a cult?)&lt;/p&gt;
&lt;p&gt;Religious weirdness aside, having complete control of the site generator made it fun again to &lt;a href=&quot;/blog/2024/07/09/microfeatures_in_my_blog&quot;&gt;tinker and add small features&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event css&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2022–2024&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Honestly though, my favorite piece of technology on the blog is &lt;a href=&quot;/blog/tags/css/&quot;&gt;CSS&lt;/a&gt;.
I just really like to spend time to fiddle with &lt;a href=&quot;/blog/2023/10/04/giving_the_blog_a_facelift/&quot;&gt;the design&lt;/a&gt; and to make small tweaks here and there.
I do use &lt;a href=&quot;https://sass-lang.com/&quot;&gt;Sass&lt;/a&gt; but 95% is just plain CSS.&lt;/p&gt;
&lt;p&gt;Modern CSS is honestly great.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event djot&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;February 2024&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;Almost by accident I &lt;a href=&quot;/blog/2024/02/02/blogging_in_djot_instead_of_markdown&quot;&gt;started using Djot&lt;/a&gt; instead of Markdown to write my posts.
I couldn’t find a Tree-sitter grammar for Djot &lt;a href=&quot;/blog/2024/03/19/lets_create_a_tree-sitter_grammar&quot;&gt;so I created one&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;event neovim&quot;&gt;
      &lt;svg class=&quot;marker&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12&quot; height=&quot;12&quot;&gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot; /&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;May 2024&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
        
&lt;p&gt;I’m in the process of &lt;a href=&quot;/series/extending_neovim_for_my_blog/&quot;&gt;connecting the site generator to Neovim&lt;/a&gt; to provide autocomplete, diagnostics, jumping between posts, and other cool features.&lt;/p&gt;
&lt;p&gt;There’s lots of potential for spending &lt;em&gt;tons&lt;/em&gt; of time in this swamp but these IDE-like features really elevate the writing experience.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;At the moment the blogging software is a whole project in and of itself (by design; it’s a fun project to tinker with).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Posts-have-changed-focus-and-increased-in-scope&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Posts-have-changed-focus-and-increased-in-scope&quot; class=&quot;heading-ref&quot;&gt;Posts have changed focus and increased in scope&lt;/a&gt;&lt;/h2&gt;
&lt;p before_date=&quot;2024-09-01&quot; caption=&quot;Posts mapped by published date and word count, grouped into lose categories. (You&apos;ll need CSS enabled to view the Graph in a nice way.)&quot;&gt;:post-stats-graph:&lt;/p&gt;
&lt;p&gt;It probably comes as no surprise that my posts have changed a lot since I started the blog.
I made the above visualization that counts the words of each post and plots them on a time axis, together with loose grouping of the type of post.&lt;/p&gt;
&lt;p&gt;I have two main takeaways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The posts have grown larger and more ambitious.&lt;/p&gt;
&lt;p&gt;In the beginning I treated the blog almost like a Twitter/X feed with short updates on my game making progress.
Now I spend weeks or even months slowly working away on a post until I feel it’s interesting and polished enough to publish.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As my interests have changed, so has the focus of my posts.&lt;/p&gt;
&lt;p&gt;I only write about my hobbies or things that I’m interested in at that moment so it’s only natural that the theme of the posts have changed.
Gaming related posts have given way for more programming and the occasional meat-space related project.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;section id=&quot;What-does-the-future-bring&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#What-does-the-future-bring&quot; class=&quot;heading-ref&quot;&gt;What does the future bring?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I find almost find it obvious that the blog has changed so much during the 15 years of it’s existence; &lt;em&gt;of course&lt;/em&gt; my posts would grow more ambitious as my writing matured and I’d &lt;em&gt;obviously&lt;/em&gt; start gravitating away from games towards other projects.&lt;/p&gt;
&lt;p&gt;Naturally, it’s just a lie I tell myself with the benefit of hindsight.&lt;/p&gt;
&lt;p&gt;Predicting the future is impossible and I have no idea what the blog will look like 15 years from now.
While it &lt;em&gt;feels&lt;/em&gt; like I’ll keep blogging the same way, it would be foolish to claim that as a fact.&lt;/p&gt;
&lt;p&gt;Sometimes it’s best to stop worrying and just enjoy the ride.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content></entry><entry><title>A simple timeline using CSS flexbox</title><id>http://jonashietala.se/blog/2024/08/25/a_simple_timeline_using_css_flexbox/index.html</id><updated>2025-01-19T07:16:57+00:00</updated><link href="https://www.jonashietala.se/blog/2024/08/25/a_simple_timeline_using_css_flexbox" rel="alternate"/><published>2024-08-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;As I added a &lt;a href=&quot;/now&quot;&gt;/now&lt;/a&gt; page to the site I also decided to refresh my &lt;a href=&quot;/about&quot;&gt;/about&lt;/a&gt; page and I figured it would be neat to have timeline element where I could list some of the larger events in my life.&lt;/p&gt;
&lt;p&gt;To my surprise it wasn’t too difficult to create one that looks pretty clean—the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox&quot;&gt;flexbox&lt;/a&gt; feature in CSS is really good.
In this post I’ll walk you through how I made this kind of timeline:&lt;/p&gt;
&lt;div class=&quot;timeline-done&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;If you’re reading this post in a feed reader then the embedded HTML examples (such as the above) won’t show up correctly.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Markup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Markup&quot; class=&quot;heading-ref&quot;&gt;Markup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like to start with the markup before moving on to styling.
I have two wrappers (&lt;code&gt;timeline&lt;/code&gt; and &lt;code&gt;events&lt;/code&gt;) around the different events (&lt;code&gt;event&lt;/code&gt;) that contains the event marker (&lt;code&gt;svg&lt;/code&gt;) and content with a &lt;code&gt;time&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;timeline&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block html&quot;&gt;&lt;span class=&quot;punctuation definition comment begin html&quot;&gt;&amp;lt;!--&lt;/span&gt; The first `1989` event &lt;span class=&quot;punctuation definition comment end html&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;event life&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment block html&quot;&gt;&lt;span class=&quot;punctuation definition comment begin html&quot;&gt;&amp;lt;!--&lt;/span&gt; The circle is an svg &lt;span class=&quot;punctuation definition comment end html&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;svg&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;12&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;12&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;circle&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;cx&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;6&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;cy&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;6&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;6&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment block html&quot;&gt;&lt;span class=&quot;punctuation definition comment begin html&quot;&gt;&amp;lt;!--&lt;/span&gt; The event info &lt;span class=&quot;punctuation definition comment end html&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;1989&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;I was born in the north of Sweden&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block html&quot;&gt;&lt;span class=&quot;punctuation definition comment begin html&quot;&gt;&amp;lt;!--&lt;/span&gt; etc ... &lt;span class=&quot;punctuation definition comment end html&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;A-simple-line&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#A-simple-line&quot; class=&quot;heading-ref&quot;&gt;A simple line&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s start with the actual line in the timeline.
I chose to use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::before&quot;&gt;::before&lt;/a&gt; pseudo-element on the &lt;code&gt;events&lt;/code&gt; div to simulate a line by setting the width and height:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-element css&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;before&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; We need some content for the element to show up.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;content&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string quoted double css&quot;&gt;&lt;span class=&quot;punctuation definition string begin css&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end css&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Use absolute positioning to place the timeline at the very top.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;absolute&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; With a height and with the timeline will be a tall and thin box.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;height&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also need to set the wrapper 
&lt;code class=&quot;highlight scss&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; to use relative positioning, otherwise the timeline will start from the top of the page, not the container:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’ll also throw in a little bit of styling so it’s easier to see:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; For the tutorial I use slightly different colors,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; but you get the idea.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-element css&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;before&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;background&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant color w3c standard css&quot;&gt;white&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Events use different classes to differentiate them.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;life&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;fill&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant color w3c standard css&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;programming&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;fill&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant color w3c extended css&quot;&gt;magenta&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;family&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;fill&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant color w3c standard css&quot;&gt;red&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Make the time stand out
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;content&lt;/span&gt; &lt;span class=&quot;entity name tag html css&quot;&gt;time&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-family&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string unquoted css&quot;&gt;concourse_4&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string unquoted css&quot;&gt;Helvetica&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;sans-serif&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-weight&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;bold&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Just some extra spacing to make the timeline not merge
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; with the surrounding text.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;5&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we have our line for our timeline:&lt;/p&gt;
&lt;div class=&quot;timeline-1&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Alignment&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Alignment&quot; class=&quot;heading-ref&quot;&gt;Alignment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The circle and event aren’t aligned, let’s try to fix that.&lt;/p&gt;
&lt;p&gt;By using flexbox the event will display its content horizontally (with the circle to the left and the content to the right):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;flex&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Close, but the circle seems off.
Remember that the circle is an svg 12 pixels wide and high and positioning will use &lt;code&gt;0,0&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;With relative positioning we can move the center of the circle to align it better:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But if you look closely this still doesn’t look correct.
Turns out that &lt;a href=&quot;https://tonsky.me/blog/centering/&quot;&gt;centering things is the hardest problem in computer science&lt;/a&gt;, so don’t be discouraged.&lt;/p&gt;
&lt;p&gt;To save you some grief, I found that &lt;code&gt;align-items: baseline&lt;/code&gt; does a better job than nudging top positioning:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;align-items&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;baseline&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3 timeline-4&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(The alignment looks good enough to me, at least with the default font I use.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Vertical-spacing&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Vertical-spacing&quot; class=&quot;heading-ref&quot;&gt;Vertical spacing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It feels a bit cramped so lets space things out.
One way is to simply add a 
&lt;code class=&quot;highlight scss&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-bottom&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; but that would add a useless space below the last event (that we’d have to remove another way).&lt;/p&gt;
&lt;p&gt;I think a cleaner way is to use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox&quot;&gt;flexbox&lt;/a&gt; and &lt;code&gt;row-gap&lt;/code&gt; to only specify spacing between elements:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;timeline-5&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;flex&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Lay out events column-wise instead of row-wise.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;flex-direction&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;column&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Set some spacing between elements.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;row-gap&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3 timeline-4 timeline-5&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Making-it-responsive&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Making-it-responsive&quot; class=&quot;heading-ref&quot;&gt;Making it responsive&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What we’ve made is good for smaller screens but for larger screens I’d like to place the line in the middle and move some events to the left and some to the right.&lt;/p&gt;
&lt;p&gt;I’ll use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries&quot;&gt;media queries&lt;/a&gt; to create a cutoff:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta at-rule media css&quot;&gt;&lt;span class=&quot;keyword control directive css&quot;&gt;&lt;span class=&quot;punctuation definition keyword css&quot;&gt;@&lt;/span&gt;media&lt;/span&gt; &lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type property-name css&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;700&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Styling for wider screens goes here.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Even though I won’t include the media query in the following code snippets the media query should wrap them all.&lt;/p&gt;
&lt;section id=&quot;Events-to-the-left&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Events-to-the-left&quot; class=&quot;heading-ref&quot;&gt;Events to the left&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first thing I’d like to do is move the line to the middle:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-element css&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;before&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; This centers the line horizontally.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Remember that we used absolute positioning before.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3 timeline-4 timeline-5 timeline-6&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(Use a wider screen to see the effects of our changes.)&lt;/p&gt;
&lt;p&gt;Now, let’s move the marker to the timeline.
First lets move the marker to be after the content in the layout ordering:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;order&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3 timeline-4 timeline-5 timeline-6 timeline-7&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Secondly, we’ll make the content take up all the space to the left, pushing the marker on top of the line in the middle:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;content&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3 timeline-4 timeline-5 timeline-6 timeline-7 timeline-8&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Lets move right-align the content and add some padding so the text won’t overlap with the marker:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;content&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;text-align&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;right&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding-inline&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3 timeline-4 timeline-5 timeline-6 timeline-7 timeline-8 timeline-9&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Events-to-the-right&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Events-to-the-right&quot; class=&quot;heading-ref&quot;&gt;Events to the right&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To move events to the right side of the timeline all we have to do is tell &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox&quot;&gt;flexbox&lt;/a&gt; to lay out elements from right to left instead of left to right:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Use `nth-child(even)` to target every other event.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;nth-child&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;even&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Layout elements from right to left.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;flex-direction&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;row-reverse&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;For the blog I don’t use &lt;code&gt;nth-child(even)&lt;/code&gt; as I prefer to group events to either side by type:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;is&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;programming&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;work&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;projects&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;flex-direction&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;row-reverse&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;To make it look good lets add left aligned text and move the marker offset to be aligned over the line again:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;nth-child&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;even&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;content&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;text-align&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; The marker used to be offset -6px, but now we
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; move from the right.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;timeline-1 timeline-2 timeline-3 timeline-4 timeline-5 timeline-6 timeline-7 timeline-8
  timeline-9 timeline-10&quot;&gt;
  &lt;div class=&quot;events&quot;&gt;
    &lt;div class=&quot;event life&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;1989&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I was born in the north of Sweden&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event programming&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;2006&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;I got introduced to Visual Basic&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;event family&quot;&gt;
      &lt;svg
        class=&quot;marker&quot;
        xmlns=&quot;http://www.w3.org/2000/svg&quot;
        width=&quot;12&quot;
        height=&quot;12&quot;
      &gt;
        &lt;circle cx=&quot;6&quot; cy=&quot;6&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;
      &lt;/svg&gt;
      &lt;div class=&quot;content&quot;&gt;
        &lt;time&gt;August 2008&lt;/time&gt;
        &lt;div class=&quot;text&quot;&gt;
          &lt;p&gt;Got together with Veronica&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Were-done&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Were-done&quot; class=&quot;heading-ref&quot;&gt;We’re done&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That’s all there is to the timeline I use.
You can of course modify and expand on it in many ways but I quite like this simple styling.&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox&quot;&gt;flexbox&lt;/a&gt; it was in the end fairly simple to get a basic timeline created and it’s one of my absolute favorite CSS features that manages to simplify many things that used to be very awkward.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Here’s the all the styling for the timeline we created in this post:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; The line in the middle.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-element css&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;before&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;content&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string quoted double css&quot;&gt;&lt;span class=&quot;punctuation definition string begin css&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end css&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;absolute&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;height&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;background&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--color-hr&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Needed for positioning the line.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Add some space.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;flex&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;5&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;flex-direction&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;column&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;row-gap&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Layout content and marker using flexbox.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;flex&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Align marker vertically.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;align-items&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;baseline&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Adjust marker to center on the line.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Some coloring to make our life easier.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;life&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;fill&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--melange_b_yellow&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;programming&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;fill&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--melange_b_magenta&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;event&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;family&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;marker&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;fill&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--melange_b_red&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;content&lt;/span&gt; &lt;span class=&quot;entity name tag html css&quot;&gt;time&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-family&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string unquoted css&quot;&gt;concourse_4&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string unquoted css&quot;&gt;Helvetica&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;sans-serif&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-weight&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;bold&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta at-rule media css&quot;&gt;&lt;span class=&quot;keyword control directive css&quot;&gt;&lt;span class=&quot;punctuation definition keyword css&quot;&gt;@&lt;/span&gt;media&lt;/span&gt; &lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type property-name css&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;700&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Place the line in the middle.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;events&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-element css&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;before&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Layout the marker after the content.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  .event .marker &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;order&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  .event .content &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Make the content take 50% space so the marker
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; will be placed at 50% (on top of the line).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Event is to the left, align text towards the line.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;text-align&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;right&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Avoid overlap with the marker.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding-inline&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; For these types, move the event to the right.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  .event:is&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;.programming&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; .work&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; .projects) &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Layout the content and marker from right to left.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;flex-direction&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;row-reverse&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Now align text to the left.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;    &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;content&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;text-align&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; We used to offset the marker from the left with -6px,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; now we need to do it from the other side.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    .marker &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
</content></entry><entry><title>Microfeatures in my blog</title><id>http://jonashietala.se/blog/2024/07/09/microfeatures_in_my_blog/index.html</id><updated>2026-04-27T10:16:47+00:00</updated><link href="https://www.jonashietala.se/blog/2024/07/09/microfeatures_in_my_blog" rel="alternate"/><published>2024-07-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/nerd_sniping.png&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://xkcd.com/356/&quot;&gt;xkcd: Nerd sniping&lt;/a&gt;
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;A while I ago I encountered a blog post called &lt;a href=&quot;https://danilafe.com/blog/blog_microfeatures/&quot;&gt;Microfeatures I Love in Blogs and Personal Websites&lt;/a&gt;, and together with the related &lt;a href=&quot;https://news.ycombinator.com/item?id=40774277&quot;&gt;Hacker News discussion&lt;/a&gt; I got &lt;a href=&quot;https://xkcd.com/356/&quot;&gt;nerd sniped&lt;/a&gt;.
(I spent more time than I care to admit implementing new and exciting microfeatures for the blog.)&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Microfeatures-are-fun-and-time-consuming&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Microfeatures-are-fun-and-time-consuming&quot; class=&quot;heading-ref&quot;&gt;Microfeatures are fun and time consuming&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For some people, blogging is their job.
For me, blogging is a way to delve deeper into ideas, to document my journey to future me, to relax, or have fun.
Microfeatures are &lt;em&gt;fun&lt;/em&gt; and so they’re a perfect fit for my blog.&lt;/p&gt;
&lt;p&gt;I also really appreciate microfeatures in other blogs.
It’s nice to &lt;a href=&quot;https://www.evalapply.org/posts/n-ways-to-fizzbuzz-in-clojure/index.html&quot;&gt;discover a beautiful table of content&lt;/a&gt; or a &lt;a href=&quot;https://jvns.ca/categories/favorite/&quot;&gt;page with favorite blog posts&lt;/a&gt;.
It makes me want to stick around longer and appreciate the craft that is blogging.&lt;/p&gt;
&lt;p&gt;But realize that microfeatures take time to implement.
One small feature won’t make a big difference but dozens of microfeatures might transform your blog rewrite you thought were going to take a weekend, to a project spanning weeks or even months.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Microfeatures-Ive-implemented&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Microfeatures-Ive-implemented&quot; class=&quot;heading-ref&quot;&gt;Microfeatures I’ve implemented&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s a collection of notable microfeatures I’ve implemented for the blog.
It’s not an exhaustive list, just the ones I think are fun, interesting, or that I’d like to see in more blogs.&lt;/p&gt;
&lt;section id=&quot;Published-and-revision-info&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Published-and-revision-info&quot; class=&quot;heading-ref&quot;&gt;Published and revision info&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There’s a trend for blog posts to not include the date the post was published—and I hate it, &lt;em&gt;especially&lt;/em&gt; for technical content.
I don’t even like to call the date of publishing a “micro” feature as it’s more an essential feature.&lt;/p&gt;
&lt;p&gt;Regardless, I include the published date below the post title in my blog:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/with_published_date.png&quot;&gt;
&lt;figcaption&gt;The published date together with the Git commit.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I also think it’s valuable to display the date the post was updated:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/with_rev_date.png&quot;&gt;
&lt;figcaption&gt;The date of the last revision together with the corresponding Git commit.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I guess it would be more precise to manually specify when the post was updated, to avoid changes like &lt;a href=&quot;https://codeberg.org/treeman/jonashietala/commit/011cebb16131566a186b1fe7c8ba884890a688d6&quot;&gt;Enclose titles in “, now an error after Hakyll update&lt;/a&gt; where the post content isn’t changed in a meaningful way.
It’s too bothersome to remember though so I rely on the Git history and have a list of commits I ignore when I fetch the dates.
Not perfect but good enough I think.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Quote-attribution&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Quote-attribution&quot; class=&quot;heading-ref&quot;&gt;Quote attribution&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The only true wisdom is in knowing you know nothing.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Socrates
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;Blockquotes are standard everywhere but you often want to show where the quote originates from.&lt;/p&gt;
&lt;p&gt;I think it’s nicer to have specific styling for attributes than to solve it manually, like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The only true wisdom is in knowing you know nothing.&lt;br&gt;
— Socrates&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/section&gt;
&lt;section id=&quot;Different-kinds-of-notes&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Different-kinds-of-notes&quot; class=&quot;heading-ref&quot;&gt;Different kinds of notes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’m a fan of sidenotes and &lt;a href=&quot;/blog/2019/03/04/pollen_sidenotes&quot;&gt;I used them&lt;/a&gt; heavily &lt;a href=&quot;https://whycryptocurrencies.com/toc.html&quot;&gt;in the book I wrote&lt;/a&gt;.
They’re great for a certain style of content but for the blog I noticed I used them very rarely.
Instead I use “notes” of different kinds to highlight certain things:&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;This is a regular note.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update &lt;span class=&quot;date&quot;&gt;2002-01-12&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;If I want to make a correction I can add a note with a timestamp.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;Did you know that you can &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;check out the source&lt;/a&gt; of this site to see how the features are implemented?&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;It’s easy to spend a lot of time building features for the blog instead of actually writing.&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;Building features just for the sake of building is perfectly fine!&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Maybe a weird thing to prioritize in a post but I really like the additional color splash the notes can give to a post.&lt;/p&gt;
&lt;p&gt;I also have footnotes&lt;a id=&quot;fnref1&quot; href=&quot;#fn1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; (mostly because &lt;a href=&quot;https://djot.net/&quot;&gt;Djot&lt;/a&gt; provides them by default) but I never really use them.
I guess I should use footnotes more now that I have them.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Enhanced-code-snippets&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Enhanced-code-snippets&quot; class=&quot;heading-ref&quot;&gt;Enhanced code snippets&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;src&amp;#x2F;markup&amp;#x2F;djot&amp;#x2F;code.rs&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;14&quot;&gt;&lt;span class=&quot;meta enum rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type enum rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;entity name enum rust&quot;&gt;Code&lt;/span&gt;&amp;lt;&amp;#39;a&amp;gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;15&quot;&gt;    Inline &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;16&quot;&gt;        code&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot;17&quot;&gt;        lang&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Option&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;18&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;19&quot;&gt;    Block &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;20&quot;&gt;        code&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;21&quot;&gt;        lang&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Option&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot;22&quot;&gt;        path&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Option&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot;23&quot;&gt;        linenum_start&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Option&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;data-linenum=&quot;24&quot;&gt;        highlight_lines&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Option&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;RangeSet&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;25&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Embedding code into blogs is common practice and I’ve added a few extra features to the code display on my blog:&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;Overlay the language or file path.&lt;/p&gt;
&lt;p&gt;For code blocks there’s a small &lt;a href=&quot;/blog/2023/10/06/language_spec_in_code_blocks&quot;&gt;description that displays the language&lt;/a&gt;.
It can be customized to for example display the path of the file:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/code_descr.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;It’s accomplished using CSS with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes&quot;&gt;data attributes&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::before&quot;&gt;::before&lt;/a&gt;, and won’t be visible in the RSS feed.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;View the source Luke.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Syntax highlight for inline code elements.&lt;/p&gt;
&lt;p&gt;Highlighting code blocks is standard but I wonder, why don’t we also highlight inline code?&lt;/p&gt;
&lt;p&gt;It’s something I added to be able to refer back to values like 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;-NoHU&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;, 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;&lt;/code&gt;, and 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.builtin&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_files()&lt;/code&gt; when explaining what happens inside a code block.
A sentence with color is much more pleasing than the colorless &lt;code&gt;&quot;-NoHU&quot;&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, and &lt;code&gt;require(&quot;telescope.builtin&quot;).find_files()&lt;/code&gt; don’t you think?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ability to highlight lines.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;css&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight css&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;punctuation separator combinator css&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;line&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;hl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line hl&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;background-color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;meta function-call css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type custom-property css&quot;&gt;&lt;span class=&quot;punctuation definition custom-property css&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;support type custom-property name css&quot;&gt;melange_a_sel&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Benjamin Tan’s excellent &lt;a href=&quot;https://ofcr.se/jujutsu-merge-workflow&quot;&gt;blog post about Jujutsu&lt;/a&gt; used highlighted lines to good effect and inspired me to implement them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Line numbers with offset.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;css&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight css&quot;&gt;&lt;div class=&quot;line&quot;data-linenum=&quot; 9&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;punctuation separator combinator css&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;line&lt;/span&gt;&lt;span class=&quot;meta attribute-selector css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;entity other attribute-name css&quot;&gt;data-linenum&lt;/span&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;::&lt;/span&gt;before&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;10&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;content&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;meta function-call css&quot;&gt;&lt;span class=&quot;support function attr css&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;entity other attribute-name css&quot;&gt;data-linenum&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;11&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding-right&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;meta function-call css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type custom-property css&quot;&gt;&lt;span class=&quot;punctuation definition custom-property css&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;support type custom-property name css&quot;&gt;space-2xs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;12&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;meta function-call css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type custom-property css&quot;&gt;&lt;span class=&quot;punctuation definition custom-property css&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;support type custom-property name css&quot;&gt;melange_a_ui&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation definition group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;data-linenum=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Line numbers is another feature I’ve recently implemented that I &lt;em&gt;think&lt;/em&gt; is a good idea.
Them being optional is important as line numbers adds visual bloat.
I’ll probably only use them in very specific scenarios where I really want to call out code at certain lines.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;The selector at line 9 targets lines with the linenum &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes&quot;&gt;data attribute&lt;/a&gt; to avoid the padding at line 11 to apply to code blocks without line numbers.&lt;/p&gt;
&lt;p&gt;Adding line numbers in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::before&quot;&gt;::before&lt;/a&gt; has the additional benefit of the line numbers not being included in the selection, so copying the code works as expected.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No images, no JavaScript, and no embedded Gists.&lt;/p&gt;
&lt;p&gt;It frustrates me to no end when someone has made the effort to write a good blog post and then use &lt;em&gt;images&lt;/em&gt; for their code.
Images inevitably fail to render as crisply as regular text and they’re either too small, too blurry, or impossible to read on the phone.&lt;/p&gt;
&lt;p&gt;I also really dislike requiring JavaScript just for displaying text or embedding code as &lt;a href=&quot;https://docs.github.com/en/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists&quot;&gt;GitHub Gists&lt;/a&gt;.
It’s just text—let’s serve it as text.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;I’ve gotten email at work with images of code they expected me to copy.
That’s &lt;a href=&quot;https://www.youtube.com/watch?v=2mtTBtMXNkg&quot;&gt;Office Space thriller&lt;/a&gt; material and such behavior will earn you enemies for life.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Table-of-content&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Table-of-content&quot; class=&quot;heading-ref&quot;&gt;Table of content&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I can optionally insert a table of contents by including a &lt;code&gt;:table-of-content:&lt;/code&gt; marker in the markup.
It uses the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details&quot;&gt;&amp;lt;details&amp;gt;&lt;/a&gt; element and is collapsed by default.
When expanded it looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/toc.png&quot;&gt;
&lt;figcaption&gt;Expanded table of content for &lt;a href=&quot;/blog/2024/03/19/lets_create_a_tree-sitter_grammar&quot;&gt;Let’s create a Tree-sitter grammar&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It’s important for me that the table of content is optional as I have a mix of small and large posts.
The table of content is generated from the first two heading levels and it works quite well for my use-case.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Flex-and-gallery-display-for-images&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Flex-and-gallery-display-for-images&quot; class=&quot;heading-ref&quot;&gt;Flex and gallery display for images&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I sometimes want to display two or more images next to each other.
Instead of having images embedded like normal I place two or more images in a 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; and use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox&quot;&gt;flexbox&lt;/a&gt; to place them next to each other:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/hextraction/fancy_board.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/fancy_board.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/hextraction/modular_board.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/modular_board.jpg&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Two boards for a game called &lt;a href=&quot;https://www.playhextraction.com/&quot;&gt;Hextraction&lt;/a&gt; that I &lt;a href=&quot;/blog/2024/02/09/printing_hextraction_for_my_kids&quot;&gt;3D printed&lt;/a&gt;.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When I have more images I use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout&quot;&gt;CSS grid&lt;/a&gt; to create a small gallery:&lt;/p&gt;
&lt;figure class=&quot;gallery&quot;&gt;
&lt;a href=&quot;/images/trap14/Robot_0001.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trap14/Robot_0001.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0002.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trap14/Robot_0002.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0005.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trap14/Robot_0005.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0010.JPG&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trap14/Robot_0010.JPG&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0012.JPG&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trap14/Robot_0012.JPG&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0013.JPG&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trap14/Robot_0013.JPG&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Pictures of a robot project from my time at the University.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Embedding-YouTube-thumbnails&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Embedding-YouTube-thumbnails&quot; class=&quot;heading-ref&quot;&gt;Embedding YouTube thumbnails&lt;/a&gt;&lt;/h3&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=eoKDyhxCVm0&quot;&gt;https://www.youtube.com/watch?v=eoKDyhxCVm0&lt;/a&gt;
&lt;p&gt;The recommended way to embed YouTube videos is to use iframes and it’s something &lt;a href=&quot;/blog/2014/09/01/embedding_youtube_videos_with_hakyll&quot;&gt;I implemented over a decade ago&lt;/a&gt;.
It works but it’s not a great solution.
Embedding anything from Google is an enabler for their all-encompassing privacy violations and &lt;a href=&quot;https://frontendmasters.com/blog/youtube-embeds-are-bananas-heavy-and-its-fixable/&quot;&gt;YouTube embeds are bananas heavy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instead I embed an image generated from the video (served from my site, not YouTube) and make it a link that takes you to YouTube.
I could’ve used JavaScript to convert the placeholder into an embedded video when clicked but I like simplicity and redirecting to YouTube allows third-party players to handle the redirect.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Different-list-types&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Different-list-types&quot; class=&quot;heading-ref&quot;&gt;Different list types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I like lists and I have several different types I can use to mix things up a bit.&lt;/p&gt;
&lt;p&gt;Here are some ordered list types:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
One
&lt;/li&gt;
&lt;li&gt;
Two
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
Alpha 1
&lt;/li&gt;
&lt;li&gt;
Alpha 2
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol type=&quot;i&quot;&gt;
&lt;li&gt;
Roman 1
&lt;/li&gt;
&lt;li&gt;
Roman 2
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;greek&quot;&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
Alpha
&lt;/li&gt;
&lt;li&gt;
Beta
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;p&gt;And here are some unordered list types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Bullet
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;dash&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Dash
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;plus&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
Plus
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Necessary? No.&lt;br&gt;
Fun? I think so.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Unbroken-indexes-of-all-posts&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Unbroken-indexes-of-all-posts&quot; class=&quot;heading-ref&quot;&gt;Unbroken indexes of all posts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Under &lt;a href=&quot;/archive&quot;&gt;/archive&lt;/a&gt; I have a list of all posts so it’s easy to scroll through and get an overview of what I’ve written about during the 15 years the blog has been active.&lt;/p&gt;
&lt;p&gt;Naturally there’s no pagination so you can just scroll through.
I only have &lt;em&gt;279&lt;/em&gt; posts… What’s the point of pagination anyway?&lt;/p&gt;
&lt;p&gt;There’s also indexes for &lt;a href=&quot;/blog/tags&quot;&gt;tags&lt;/a&gt; (see &lt;a href=&quot;/blog/tags/keyboards&quot;&gt;keyboards&lt;/a&gt;) and per year (see &lt;a href=&quot;/blog/2023&quot;&gt;2023&lt;/a&gt;).
The yearly index mostly exists so I have an easy way to see the past years posts when I do my &lt;a href=&quot;/blog/tags/yearly_review&quot;&gt;yearly review&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Featured-favorite-posts&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Featured-favorite-posts&quot; class=&quot;heading-ref&quot;&gt;Featured &amp;amp; favorite posts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Highlighting favorite posts is a good idea I got from the &lt;a href=&quot;https://news.ycombinator.com/item?id=40774277&quot;&gt;Hacker News discussion&lt;/a&gt; and one I just had to implement after seeing it.
I handle featured and favorite posts in three ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I list five featured posts on the homepage:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/featured_posts.png&quot;&gt;
&lt;figcaption&gt;Featured posts on the homepage.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;A featured post isn’t the same as a favorite post, although the featured posts tend to be favorites.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All favorite posts are listed under &lt;a href=&quot;/favorite&quot;&gt;/favorite&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Each favorite post is accompanied by a star: 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;favorite&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/favorite&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;★&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/archive_favs.png&quot;&gt;
&lt;figcaption&gt;A post listing from the &lt;a href=&quot;/archive&quot;&gt;archives&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Clicking on the star takes you to &lt;a href=&quot;/favorite&quot;&gt;/favorite&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Series&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Series&quot; class=&quot;heading-ref&quot;&gt;Series&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tags are fine for grouping slightly related posts but sometimes posts follow a more structured story, which is where &lt;a href=&quot;/series&quot;&gt;series&lt;/a&gt; come in.&lt;/p&gt;
&lt;p&gt;A good example of a series is the &lt;a href=&quot;/series/voron_trident&quot;&gt;Let’s build a VORON Trident&lt;/a&gt; where I document my journey of building my first 3D printer over 12 posts.&lt;/p&gt;
&lt;p&gt;There’s a few features that come with a series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;All series, both ongoing and completed, are listed under &lt;a href=&quot;/series&quot;&gt;/series&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Each series gets a separate page with a description and the list of posts.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;/series/voron_trident&quot;&gt;/series/voron_trident&lt;/a&gt; or &lt;a href=&quot;/series/t-34&quot;&gt;/series/t-34&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A post is clearly marked as belonging to a series.&lt;/p&gt;
&lt;p&gt;It’s marked next to the post title:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/series_post_title.png&quot;&gt;
&lt;figcaption&gt;The series is marked both above and below the post title.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;And more information about the series is included at the end of the post, so it’s easy to jump around in the series:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/series_post_end.png&quot;&gt;
&lt;figcaption&gt;All posts in the series are included at the end of a post.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Selected series are showcased on the homepage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I like series and I want to write more series.
The drawback is that they take more effort to create than standalone blog posts.
As my attention and motivation tends to shift a lot this increases the &lt;a href=&quot;/blog/2023/03/14/battling_burnout&quot;&gt;risk of stress&lt;/a&gt; if I lose motivation in the middle of a series.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Projects&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Projects&quot; class=&quot;heading-ref&quot;&gt;Projects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While a blog is about writing I also wanted to highlight some of the personal projects I’ve made.&lt;/p&gt;
&lt;p&gt;There are no individual pages for the projects as they typically live outside this site (maybe at Codeberg).
Instead I have a &lt;a href=&quot;/projects&quot;&gt;/projects&lt;/a&gt; page with the projects and I include a subset of those on the homepage.&lt;/p&gt;
&lt;p&gt;The projects markup is fairly simple, just a title and a description (that could include an image, code block, or whatever):&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/t34_project.png&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;/series/t-34/&quot;&gt;T-34 Keyboard layout&lt;/a&gt; project.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Long ago I made some game prototypes and I wanted to showcase them in a slightly different manner.
They’re still included as a project but they get specialized markup that I’m pretty happy with:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/games.png&quot;&gt;
&lt;figcaption&gt;The games overview in the &lt;a href=&quot;/projects&quot;&gt;/projects&lt;/a&gt; page.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Automatic-dark-mode&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Automatic-dark-mode&quot; class=&quot;heading-ref&quot;&gt;Automatic dark mode&lt;/a&gt;&lt;/h3&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/microfeatures/djot_light.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/djot_light.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/microfeatures/djot_dark.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/microfeatures/djot_dark.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;The light and dark style of the site.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Because I have a preference for dark mode I really wanted a dark mode for the blog, while also catering to people that prefers a light mode.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2023/10/04/giving_the_blog_a_facelift/#automatic-dark-mode&quot;&gt;I implemented&lt;/a&gt; dark mode using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme&quot;&gt;prefers-color-scheme&lt;/a&gt;, a simple solution that doesn’t require JavaScript and “just works”.
It’s a CSS feature that allows the user to specify their preference using the browser or operating system.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Microfeatures-I-may-implement-in-the-future&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Microfeatures-I-may-implement-in-the-future&quot; class=&quot;heading-ref&quot;&gt;Microfeatures I may implement in the future&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Naturally, there’s always more features you can implement.
Many I won’t bother with but there are some that I think are good ideas and that I may implement one day.&lt;/p&gt;
&lt;section id=&quot;Targeted-RSS-feeds&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Targeted-RSS-feeds&quot; class=&quot;heading-ref&quot;&gt;Targeted RSS feeds&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;RSS feeds are awesome and I think all blogs should have them (and news sites, social media sites… almost everything really).
I do of course &lt;a href=&quot;/feed.xml&quot;&gt;have a feed&lt;/a&gt; but it might be a good idea to add specialized feeds such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Feed for a series
&lt;/li&gt;
&lt;li&gt;
Feed for a tag
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only reason I don’t have them is laziness.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Search&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Search&quot; class=&quot;heading-ref&quot;&gt;Search&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because it’s a static site it’s harder to have a good search functionality.
Maybe there’s a good way to create/include one but I haven’t looked into it more.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;A-better-404-page&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#A-better-404-page&quot; class=&quot;heading-ref&quot;&gt;A better 404 page&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Perhaps related to the search functionality, it would be nice if the 404 page would include a helpful “did you mean” message.&lt;/p&gt;
&lt;p&gt;For example if you typed in the path &lt;code&gt;/use&lt;/code&gt; it could suggest you to try &lt;a href=&quot;/uses&quot;&gt;/uses&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;So far I’ve avoided JavaScript in the blog but here it would be nice to have.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Summary-of-a-post&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Summary-of-a-post&quot; class=&quot;heading-ref&quot;&gt;Summary of a post&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve toyed with the idea of having a summary of each post, so I could have the summary of a featured post on the homepage.
However, good summaries are cumbersome to maintain and hard to auto-generate.&lt;/p&gt;
&lt;p&gt;I don’t want to summarize manually—it introduces too much friction into blogging.
While LLMs are honestly quite good at generating summaries, I think we need less AI generated content on the web, not more.
Taking the first N characters or M paragraphs is a shoddy way of summarizing a post and won’t create a useful summary.&lt;/p&gt;
&lt;p&gt;While I like the idea of a post summary, it’s not a feature I’ll implement anytime soon.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Display-related-posts-below-the-post&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Display-related-posts-below-the-post&quot; class=&quot;heading-ref&quot;&gt;Display “related” posts below the post&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another interesting idea is to display a bunch of related posts at the end of a post.
The problem is similar to that of &lt;a href=&quot;#Summary-of-a-post&quot;&gt;summarizing a post&lt;/a&gt;: it’s cumbersome to maintain or hard to auto-generate well.
For now I’m content with &lt;a href=&quot;/blog/tags&quot;&gt;tags&lt;/a&gt; and &lt;a href=&quot;/series&quot;&gt;series&lt;/a&gt; as a means of grouping related posts.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Changelog&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Changelog&quot; class=&quot;heading-ref&quot;&gt;Changelog&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While I &lt;a href=&quot;#Published-and-revision-info&quot;&gt;display the latest Git commit&lt;/a&gt; for each post I was impressed by the list of “meaningful changes” at the bottom of the &lt;a href=&quot;https://v5.chriskrycho.com/essays/jj-init/&quot;&gt;jj init&lt;/a&gt; blog post.&lt;/p&gt;
&lt;p&gt;A changelog looks cool but I’m too lazy to maintain one for all posts.
A post like &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout&quot;&gt;The current T-34 keyboard layout&lt;/a&gt; would probably benefit from a proper changelog.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section role=&quot;doc-endnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://djot.net/&quot;&gt;Djot&lt;/a&gt; has a bunch of nice benefits over markdown such as footnotes.&lt;/p&gt;
&lt;p&gt;There are various flavors such as &lt;a href=&quot;https://pandoc.org/MANUAL.html&quot;&gt;Pandoc&lt;/a&gt; flavored markdown that has footnotes, among other things.&lt;a href=&quot;#fnref1&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><title>Back to lazy.nvim</title><id>http://jonashietala.se/blog/2024/06/25/back_to_lazynvim/index.html</id><updated>2024-06-25T07:38:52+00:00</updated><link href="https://www.jonashietala.se/blog/2024/06/25/back_to_lazynvim" rel="alternate"/><published>2024-06-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Around a month ago &lt;a href=&quot;/blog/2024/06/02/migrating_to_rocksnvim&quot;&gt;I had an affair&lt;/a&gt; with &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;.
It was fun, but I’m back together with &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; again.
This is a short post to explain why—at this point in time—the grass wasn’t greener on the other side.&lt;/p&gt;
&lt;section id=&quot;Problems-with-rocksnvim&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Problems-with-rocksnvim&quot; class=&quot;heading-ref&quot;&gt;Problems with &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Too many weird issues.&lt;/p&gt;
&lt;p&gt;I had quite a few weird bugs that I couldn’t pin down.
What finally broke the camel’s back was that &lt;a href=&quot;https://github.com/jfpedroza/neotest-elixir/issues/35&quot;&gt;I couldn’t run neotest with Elixir&lt;/a&gt;.
I think the problem was that I didn’t have the correct treesitter grammar but no matter how I tried to &lt;code&gt;:Rocks sync&lt;/code&gt;, &lt;code&gt;:Rocks update&lt;/code&gt;, &lt;code&gt;:TSInstall&lt;/code&gt;, or nuke the nvim folders in &lt;code&gt;~/.local&lt;/code&gt; and do a complete reinstall, I couldn’t get it to work.&lt;/p&gt;
&lt;p&gt;I don’t want to mess with my Neovim configuration when I’ve got work to do.
With &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; these issues went away.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update and sync was really slow.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:Rocks update&lt;/code&gt; and &lt;code&gt;:Rocks sync&lt;/code&gt; is &lt;em&gt;painfully&lt;/em&gt; slow compared to &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;.
I was already frustrated with packages breaking and having to wait for the &lt;code&gt;:Rocks sync&lt;/code&gt; to finish when I trying to fix them made me want to smash the computer to pieces.&lt;/p&gt;
&lt;p&gt;That there’s no way to &lt;code&gt;update&lt;/code&gt; or &lt;code&gt;sync&lt;/code&gt; an individual package was just gravy.&lt;/p&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update&lt;/div&gt;
&lt;p&gt;I’m told that &lt;code&gt;:Rocks install {rock}&lt;/code&gt; updates an installed package.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Lazynvim-110-supports-luarocks-and-rockspec&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Lazynvim-110-supports-luarocks-and-rockspec&quot; class=&quot;heading-ref&quot;&gt;Lazy.nvim 11.0 supports luarocks and rockspec&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;single&lt;/em&gt; reason I started looking into &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; was support for &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt; where plugins can specify their own dependencies so that I don’t have to.
&lt;a href=&quot;https://www.reddit.com/r/neovim/comments/1dng1d6/lazynvim_110_is_released_packages_luarocks_and/&quot;&gt;With 11.0&lt;/a&gt; lazy.nvim added support for &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt; including the ability to specify any &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt; dependency (such as a &lt;a href=&quot;https://luarocks.org/modules/LebJe/toml&quot;&gt;toml library&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Given that &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; supports &lt;a href=&quot;https://lazy.folke.io/spec/versioning&quot;&gt;semver versioning&lt;/a&gt; and &lt;a href=&quot;https://lazy.folke.io/usage/lockfile&quot;&gt;&lt;code&gt;:Lazy restore&lt;/code&gt;&lt;/a&gt; there are no longer any features I need that &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; have that &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; don’t.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Specifying plugins in a &lt;code&gt;.toml&lt;/code&gt; file rather than in Lua has the benefit of making it easier to create management commands like &lt;code&gt;:Rocks install&lt;/code&gt;.
It’s not something I really care about but I can see the attraction of plugin management being as simple as running a few commands.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;I-will-be-faithful-I-promise&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#I-will-be-faithful-I-promise&quot; class=&quot;heading-ref&quot;&gt;I will be faithful, I promise&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I really need my configuration to &lt;em&gt;just work&lt;/em&gt; and unfortunately that wasn’t the case for me with &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;.
That’s why I’m back to &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; and I’m really enjoying the fantastic speed of &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;.
Why did I ever leave you?&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Migrating to rocks.nvim</title><id>http://jonashietala.se/blog/2024/06/02/migrating_to_rocksnvim/index.html</id><updated>2026-04-27T15:24:59+00:00</updated><link href="https://www.jonashietala.se/blog/2024/06/02/migrating_to_rocksnvim" rel="alternate"/><published>2024-06-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rocks_nvim_files.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;My relationship with my &lt;a href=&quot;https://github.com/treeman/dotfiles/tree/master/.config/nvim&quot;&gt;Neovim config&lt;/a&gt; is best described as an &lt;a href=&quot;https://en.wikipedia.org/wiki/On-again,_off-again_relationship&quot;&gt;On-again, off-again relationship&lt;/a&gt;.
At times I’m deeply in love and spend all my time caressing the config—like how in September I &lt;a href=&quot;https://www.jonashietala.se/blog/2023/10/01/rewriting_my_neovim_config_in_lua/&quot;&gt;did a complete rewrite in Lua&lt;/a&gt;—while other times I’m busy with other love interests and the config is left alone, sometimes for months or even years.&lt;/p&gt;
&lt;p&gt;While not as intense as the September affair, I recently got back together with my config to migrate her from the “old and boring” &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; package manager to the new and exciting &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;.
It wasn’t all smooth sailing but with some patience—and a drink or two—our threesome with &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; was quite enjoyable.&lt;/p&gt;
&lt;aside class=&quot;important&quot;&gt;
&lt;p&gt;There’s nothing wrong with &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;—it’s great.&lt;br&gt;
Sometimes I just want a new experience.&lt;/p&gt;
&lt;/aside&gt;
&lt;section id=&quot;Why-rocksnvim&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Why-rocksnvim&quot; class=&quot;heading-ref&quot;&gt;Why &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To be honest, the biggest reason I started looking into &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; was that my brain—for some weird reason—tends to &lt;em&gt;get stuck&lt;/em&gt; thinking of things.
Rewriting my config wasn’t something I wanted to do but it’s not easy to escape the brain lock.&lt;/p&gt;
&lt;p&gt;Luckily, this time my brain locked onto something a worthwhile as &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; has some nice and ambitious features.&lt;/p&gt;
&lt;section id=&quot;Benefits-over-other-package-managers&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Benefits-over-other-package-managers&quot; class=&quot;heading-ref&quot;&gt;Benefits over other package managers&lt;/a&gt;&lt;/h3&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; makes dependency management the responsibility of the plugin.&lt;/p&gt;
&lt;p&gt;With other package managers you as a user have to specify the dependencies for the plugin.
Using &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; it might look like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;NeogitOrg/neogit&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   dependencies &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-lua/plenary.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-telescope/telescope.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;sindrets/diffview.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   opts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; opts,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are several issues with this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
It’s annoying.
&lt;/li&gt;
&lt;li&gt;
You need to babysit the config if the plugin adds or removes a dependency.
&lt;/li&gt;
&lt;li&gt;
The plugin might break if there’s a breaking change in a dependency.
&lt;/li&gt;
&lt;li&gt;
What if you have several plugins that depend on a different version of a dependency?
(You’re going to have a bad time.)
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; moves the dependency management to the plugin, so we can just specify the plugin itself:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rocks.toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;neo-tree.nvim&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;3.26&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This makes plugin management easier and should reduce the risk of plugins breaking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; supports loading Lua packages from &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lua is a neat little language but it’s very bare-bones and doesn’t include a large standard library.
Neovim has been incorporating more and more utility functions—such as &lt;code&gt;vim.split&lt;/code&gt; and &lt;code&gt;vim.fs.joinpath()&lt;/code&gt;—but there are still plenty of functionality that we need to import.
That’s why utility plugins such as &lt;a href=&quot;https://github.com/nvim-lua/plenary.nvim&quot;&gt;plenary.nvim&lt;/a&gt; exists and is a dependency to a lot of different plugins.&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt; you get access to many more libraries; for example a &lt;a href=&quot;https://luarocks.org/modules/gaspard/yaml&quot;&gt;yaml&lt;/a&gt; and a &lt;a href=&quot;https://luarocks.org/modules/LebJe/toml&quot;&gt;toml&lt;/a&gt; library that would’ve saved me &lt;a href=&quot;/blog/2024/05/08/browse_posts_with_telescopenvim#Finding-the-post-data-to-populate-the-picker&quot;&gt;from parsing them with regex&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Drawbacks-compared-to-lazynvim&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Drawbacks-compared-to-lazynvim&quot; class=&quot;heading-ref&quot;&gt;Drawbacks compared to &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Naturally, it’s not all fun and games and there are drawbacks to &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; compared to &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;:&lt;/p&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
&lt;p&gt;Most plugins don’t have a rockspec that define their dependencies, meaning you still need to manage the dependencies yourself, forgoing the biggest benefit of &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Installing and updating all packages feels a lot slower.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You must manage lazy loading manually. I’ve seen rumors of lazy loading support for &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; but as I’m writing this post there’s nothing released yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; is newer than &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;; meaning less fancy features, more bugs, and more rough edges.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While I think that &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; is taking a necessary and difficult step forward for Neovim package managers, there are valid reasons to stick with &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Basic-setup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Basic-setup&quot; class=&quot;heading-ref&quot;&gt;Basic setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can install &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; by manually sourcing an installer script but I wanted &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; to install itself automatically.
It’s possible by dropping &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim?tab=readme-ov-file#rocket-bootstrapping-script&quot;&gt;the bootstrap script&lt;/a&gt; into your &lt;code&gt;init.lua&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Then you’re good to go with managing plugins with the &lt;code&gt;:Rocks&lt;/code&gt; commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:Rocks install {rock}&lt;/code&gt; to install a package.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:Rocks sync&lt;/code&gt; to sync packages with &lt;code&gt;rocks.toml&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:Rocks update&lt;/code&gt; to update packages &lt;em&gt;and&lt;/em&gt; their versions in &lt;code&gt;rocks.toml&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:Rocks prune {rock}&lt;/code&gt; to uninstall a package.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was a bit surprised that you can’t update or sync an individual package but otherwise the commands feel intuitive.&lt;/p&gt;
&lt;section id=&quot;Separate-config-file-per-plugin&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Separate-config-file-per-plugin&quot; class=&quot;heading-ref&quot;&gt;Separate config file per plugin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One feature I &lt;em&gt;really&lt;/em&gt; like about &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; is the ability to separate plugin configuration into separate files.
This is easy to setup in &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; using &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-config.nvim&quot;&gt;rocks-config.nvim&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;:Rocks install rocks-config.nvim&lt;/code&gt; or edit &lt;code&gt;rocks.toml&lt;/code&gt; manually:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rocks.toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;rocks-config.nvim&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;1.6.0&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a plugin-specific file at &lt;code&gt;lua/plugins/&amp;lt;plugin-name&amp;gt;.lua&lt;/code&gt; with the plugin setup and configuration code.&lt;/p&gt;
&lt;p&gt;For example, we can install &lt;a href=&quot;https://github.com/stevearc/conform.nvim&quot;&gt;conform.nvim&lt;/a&gt; with &lt;code&gt;:Rocks install conform.nvim&lt;/code&gt; and configure it in &lt;code&gt;lua/plugins/conform.lua&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&amp;#x2F;plugins&amp;#x2F;conform.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;conform&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  formatters_by_ft &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lua &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;stylua&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;There are &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-config.nvim?tab=readme-ov-file#options&quot;&gt;some rules&lt;/a&gt; on what to name the config file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
The plugin’s name (as long as it is a valid module name).
&lt;/li&gt;
&lt;li&gt;
The plugin’s name with the &lt;code&gt;.[n]vim&lt;/code&gt; suffix removed.
&lt;/li&gt;
&lt;li&gt;
The plugin’s name with the &lt;code&gt;[n]vim-&lt;/code&gt; prefix removed.
&lt;/li&gt;
&lt;li&gt;
The plugin’s name with &lt;code&gt;-&lt;/code&gt; substituted for &lt;code&gt;.&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For &lt;a href=&quot;https://github.com/stevearc/conform.nvim&quot;&gt;conform.nvim&lt;/a&gt; we could name the config file &lt;code&gt;conform-nvim.lua&lt;/code&gt; or simply &lt;code&gt;conform.lua&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Something to keep in mind when migrating to a setup with a config file per plugin is a potential ordering issue.
I for example use &lt;a href=&quot;https://github.com/williamboman/mason-lspconfig.nvim&quot;&gt;mason-lspconfig.nvim&lt;/a&gt; for my LSP setup and it’s important to call the setup in the right order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Setup &lt;a href=&quot;https://github.com/williamboman/mason.nvim&quot;&gt;mason.nvim&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Setup &lt;a href=&quot;https://github.com/williamboman/mason-lspconfig.nvim&quot;&gt;mason-lspconfig.nvim&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Setup &lt;a href=&quot;https://github.com/neovim/nvim-lspconfig&quot;&gt;lspconfig&lt;/a&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the plugins have their own config file then we can’t guarantee this order.
We can instead setup them all in one of the config files—although I’m not a fan of commingling setup of different plugins in a single file in &lt;code&gt;lua/plugins&lt;/code&gt;, I prefer them to have a 1-to-1 relationship with a plugin.
I think it’s cleaner to place such a file in a runtimepath such as &lt;code&gt;plugin/lspconfig.lua&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Git-dependencies&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Git-dependencies&quot; class=&quot;heading-ref&quot;&gt;Git dependencies&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another crucial feature is the ability to install plugins from git repositories.
This requires the &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-git.nvim&quot;&gt;rocks-git.nvim&lt;/a&gt; module that’s installed with &lt;code&gt;:Rocks install rocks-git.nvim&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rocks.toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;rocks-git.nvim&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;1.5.1&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can then add git dependencies using &lt;code&gt;:Rocks install &amp;lt;git-path&amp;gt;&lt;/code&gt; or add them to &lt;code&gt;rocks.toml&lt;/code&gt; manually:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rocks.toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;vim-fugitive&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;tpope/vim-fugitive&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;trouble.nvim&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;folke/trouble.nvim&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;branch&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;dev&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;nvim-ts-autotag&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;windwp/nvim-ts-autotag&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;aeb7090&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As I’m writing this almost exactly half of my plugins in &lt;code&gt;rocks.toml&lt;/code&gt; depends on a git repository instead of &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt;.
Mostly because they don’t exist on &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt; but I also have some Vimscript plugins that never will be.&lt;/p&gt;
&lt;p&gt;One feature I’m missing is a command to automatically update &lt;code&gt;rev&lt;/code&gt; to the latest available value or removing it, now I did it manually.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;How-to-build-a-plugin&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#How-to-build-a-plugin&quot; class=&quot;heading-ref&quot;&gt;How to build a plugin?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are some plugins that needs to be built before we can use them in Neovim.
&lt;a href=&quot;https://github.com/nvim-telescope/telescope-fzf-native.nvim&quot;&gt;telescope-fzf-native&lt;/a&gt; is such an example where we need to run &lt;code&gt;make&lt;/code&gt; after we clone the repository.
If this plugin was on &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt; this would be managed seamlessly by &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; but since the dependency is a git repository we need to build it ourselves.&lt;/p&gt;
&lt;p&gt;I spent some time wondering how I should solve this but turns out it’s as simple as adding a &lt;code&gt;build&lt;/code&gt; option to the plugin:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rocks.toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;telescope-fzf-native.nvim&amp;quot;&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim-telescope/telescope-fzf-native.nvim&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;make&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Before I discovered the &lt;code&gt;build&lt;/code&gt; option I called &lt;code&gt;make&lt;/code&gt; the hard way:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;after&amp;#x2F;plugin&amp;#x2F;telescope-fzf-native.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nio&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).run(&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; package_path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    vim.fs.joinpath(
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      vim.fn.stdpath(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;data&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;site/pack/rocks/start&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope-fzf-native.nvim/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    )
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Before loading the extension we need to build it with `make`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nio&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).process.run({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    cmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;make&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    args &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {},
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    cwd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; package_path,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Now we can load the extension.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).load_extension(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;fzf&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s what you get if you skip the manual.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Lazy-loading&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Lazy-loading&quot; class=&quot;heading-ref&quot;&gt;Lazy loading&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One big feature that &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; promotes is lazy loading—it’s even in the name!
Unfortunately &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; doesn’t provide first-class support for lazy loading so we have to manage it ourselves.&lt;/p&gt;
&lt;section id=&quot;The-problem-with-lazy-loading&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#The-problem-with-lazy-loading&quot; class=&quot;heading-ref&quot;&gt;The problem with lazy loading&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before looking at how to implement lazy loading, I’d like to bring up a few problems with lazy loading plugins.&lt;/p&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
&lt;p&gt;It’s easy to half-ass it.&lt;/p&gt;
&lt;p&gt;For example, with &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; you can add commands and events that you want to lazy load on:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;{
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-treesitter/nvim-treesitter&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  cmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TSInstall&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TSUpdate&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  event &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufReadPre&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufNewFile&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  config &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; config,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  build &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;:TSUpdate&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But how do you know that you used the correct events and listed the right commands?
And how do you keep up to date when a plugin adds or removes commands?&lt;/p&gt;
&lt;p&gt;I managed to get &lt;strong&gt;really&lt;/strong&gt; agitated when I thought I’d messed up the treesitter installation when I couldn’t call &lt;code&gt;:TSInstallInfo&lt;/code&gt;, until I remembered that I hadn’t registered that command to load &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt;…&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/treesitter_cmds.png&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; defines a lot of commands that we ideally should list when we setup lazy loading.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extra complexity.&lt;/p&gt;
&lt;p&gt;Earlier in this post I complained about having to &lt;a href=&quot;#Benefits-over-other-package-managers&quot;&gt;manage the dependencies for the plugins&lt;/a&gt; you install.
When you lazy load a plugin you also need to specify commands and events you want to use for lazy load.&lt;/p&gt;
&lt;p&gt;And if you &lt;em&gt;really&lt;/em&gt; want to commit to lazy loading as many plugins as possible (I did!) you might end up with some pretty horrendous code, like how you’d lazy load &lt;a href=&quot;https://github.com/stevearc/oil.nvim&quot;&gt;oil.nvim&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;{
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;stevearc/oil.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  dependencies &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-tree/nvim-web-devicons&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  opts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; opts,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  command &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Oil&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; This is how to lazy load oil according to:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; https://github.com/folke/lazy.nvim/issues/533
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  init &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; vim.fn.argc() &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; stat &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.loop.fs_stat(vim.fn.argv(&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; stat &lt;span class=&quot;keyword operator lua&quot;&gt;and&lt;/span&gt; stat.type &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;directory&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;lazy&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).load({ plugins &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;oil.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;lazy.core.config&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).plugins[&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;oil.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]._.loaded &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      vim.api.nvim_create_autocmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufNew&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; vim.fn.isdirectory(vim.fn.expand(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;afile&amp;gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;lazy&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).load({ plugins &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;oil.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Once oil is loaded, we can delete this autocmd
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In general I think properly lazy loading should be the responsibility of the plugin, not us as users.&lt;/p&gt;
&lt;p&gt;With that said, being able to lazy load plugins is a great feature when you need it.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Lazy-setup-with-packadd-and-setup&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Lazy-setup-with-packadd-and-setup&quot; class=&quot;heading-ref&quot;&gt;Lazy setup with packadd and setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On a basic level you can accomplish lazy loading by following these three steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mark the plugin with 
&lt;code class=&quot;highlight lua&quot;&gt;opt &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rocks.toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;neorg&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;opt&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant builtin&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will prevent &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; from sourcing the plugin at startup.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the plugin with &lt;code&gt;packadd&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;packadd neorg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup and configure the plugin as needed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Steps 2 and 3 should be done on-demand, for example via an autocommand:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.api.nvim_create_autocmd({ &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufReadPre&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufNewFile&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  pattern &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;*.norg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;packadd neorg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;neorg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Although &lt;code&gt;packadd&lt;/code&gt; is neat, according to &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; it’s only relevant for the plugin’s &lt;code&gt;ftdetect&lt;/code&gt; and &lt;code&gt;plugin&lt;/code&gt; scripts.
I haven’t seen the need to go quite this far to get a snappy experience and right now I don’t use &lt;code&gt;packadd&lt;/code&gt; at all.
I don’t even have 100 plugins yet, I’m practically running stock Neovim!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Lazy-LSP-setup&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Lazy-LSP-setup&quot; class=&quot;heading-ref&quot;&gt;Lazy LSP setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There’s one instance where I’ve made the plugin setup lazy: the LSP config.&lt;/p&gt;
&lt;p&gt;It’s important to me that Neovim starts quickly as I have a weird workflow where I start Neovim dozens of times a day.
But after migrating my config I noticed that Neovim was feeling slow.
I tracked it down to the LSP setup (and in particular setting up &lt;a href=&quot;https://github.com/elixir-tools/elixir-tools.nvim&quot;&gt;elixir-tools.nvim&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;My solution was to create an autocommand that sources the LSP config when reading a file:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&amp;#x2F;config&amp;#x2F;lazy.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.api.nvim_create_autocmd({ &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufReadPre&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufNewFile&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  pattern &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;*&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;lazy_plugins.lspconfig&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&amp;#x2F;lazy_plugins&amp;#x2F;lspconfig.lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; mason_lspconfig &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;mason-lspconfig&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;mason_lspconfig.setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;elixir&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;mason_lspconfig.setup_handlers({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; And a bunch of other LSP related setup.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I could of course make it more granular and make more plugins lazy but I haven’t bothered since Neovim now starts under 150 ms, which my brain interprets as instant.&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;You can get info about Neovim’s startup time by passing the &lt;code&gt;--startuptime&lt;/code&gt; argument:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;nvim&lt;/span&gt; --startuptime log.txt
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here’s a shortened output of &lt;code&gt;log.txt&lt;/code&gt; where you can see the overall startup time but also how long loading packages take:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;log.txt&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;000.000  000.000: --- NVIM STARTING ---
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;028.386  000.119  000.119: require(&apos;fzy_native&apos;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;028.388  000.201  000.082: require(&apos;fzy&apos;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;130.398  000.255: before starting main loop
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;131.047  000.649: first screen update
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;131.049  000.001: --- NVIM STARTED ---
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Treesitter&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Treesitter&quot; class=&quot;heading-ref&quot;&gt;Treesitter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another feature &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; promotes is a “just works” &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;tree-sitter setup&lt;/a&gt;.
Unfortunately, I couldn’t get it to work and I instead rely on the &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; git repository.&lt;/p&gt;
&lt;p&gt;It’s likely I made some configuration error somewhere but after spending many hours reworking the entire configuration from scratch (on multiple machines) I gave up when I had a working setup.&lt;/p&gt;
&lt;ol type=&quot;i&quot;&gt;
&lt;li&gt;
&lt;p&gt;At first I tried &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;rocks-treesitter.nvim&lt;/a&gt; without &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Installing grammars using &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;rocks-treesitter.nvim&lt;/a&gt; was straightforward and worked well.
However, I use a bunch of extra features found in &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; and related packages that I need.
This &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; config activates the features:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-treesitter.configs&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  highlight &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  matchup &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  autotag &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  endwise &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  indent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  textobjects &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    move &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    swap &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support function lua&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      enable &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But I couldn’t figure out how to make these feature work using &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;rocks-treesitter.nvim&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I tried to have both &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;rocks-treesitter.nvim&lt;/a&gt; and &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; installed.&lt;/p&gt;
&lt;p&gt;That only lead to the dreaded &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter/issues/6419&quot;&gt;invalid node type&lt;/a&gt; error (meaning there’s a mismatch between the grammar and the query files).
Which kind-of makes sense as &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; provides query files for all grammars but there’s no guarantee that &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;rocks-treesitter.nvim&lt;/a&gt; installs the correct grammar for those query files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I tried to use the &lt;a href=&quot;https://luarocks.org/modules/neovim/nvim-treesitter&quot;&gt;nvim-treesitter from luarocks&lt;/a&gt; without &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;rocks-treesitter.nvim&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yet once again the Rust tree-sitter grammar hit the &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter/issues/6419&quot;&gt;invalid node type&lt;/a&gt; error.
I also couldn’t install all the grammars as a lot of them failed during installation:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;nvim-treesitter[bass]: Failed to execute the following command:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;{
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  cmd = &quot;mv&quot;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  opts = {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    args = { &quot;-f&quot;, &quot;tree-sitter-bass-tmp/tree-sitter-bass-master&quot;, &quot;tree-sitter-bass&quot; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    cwd = &quot;/home/tree/.local/share/nvim&quot;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    stdio = {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      [2] = &lt;userdata 1&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      [3] = &lt;userdata 2&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;mv: cannot stat &apos;tree-sitter-bass-tmp/tree-sitter-bass-master&apos;: No such file or directory
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Weird.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fallback to the git repository for &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; and friends.&lt;/p&gt;
&lt;p&gt;It’s surprising, because I’d assume the luarocks dev version would be the same as the GitHub source, yet this worked for me:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rocks.toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;nvim-treesitter&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim-treesitter/nvim-treesitter&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;1eabe69&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;nvim-treesitter-endwise&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;RRethy/nvim-treesitter-endwise&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;8b34305&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;nvim-ts-context-commentstring&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;JoosepAlviste/nvim-ts-context-commentstring&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;0bdccb9&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;nvim-treesitter-context&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim-treesitter/nvim-treesitter-context&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;55e2908&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;nvim-ts-autotag&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;windwp/nvim-ts-autotag&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;aeb7090&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;nvim-treesitter-textobjects&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim-treesitter/nvim-treesitter-textobjects&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;5f9bf4b&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I pin them to a revision because I got tired of things breaking.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While I can now install all grammars that &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt; provides and use all treesitter features I used before, I’m annoyed that I couldn’t make it work using &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-treesitter.nvim&quot;&gt;rocks-treesitter.nvim&lt;/a&gt;.
I’m sure there’s something obvious I’m missing but I don’t have the energy to retrace the steps again right now.
I’ll instead document my failings publicly on the blog and move on with my life.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Other-resolved-issues&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Other-resolved-issues&quot; class=&quot;heading-ref&quot;&gt;Other resolved issues&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While migrating I ran into some other minor issues that I managed to resolve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Some plugins in &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt; are outdated.&lt;/p&gt;
&lt;p&gt;For example, the last update to the &lt;a href=&quot;https://github.com/lewis6991/gitsigns.nvim&quot;&gt;luarocks gitsigns.nvim &lt;/a&gt; was made 2 years ago, while the &lt;a href=&quot;https://luarocks.org/modules/teto/gitsigns.nvim&quot;&gt;gitsigns.nvim on GitHub&lt;/a&gt; was updated this week.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Got some weird errors I couldn’t debug.&lt;/p&gt;
&lt;p&gt;For example, help for &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; wasn’t available.
A clean reinstall by removing the folders &lt;code&gt;~/.local/share/nvim/&lt;/code&gt; and &lt;code&gt;~/.cache/nvim/&lt;/code&gt; seems to have resolved the help installation and some other weird errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;:Rocks sync&lt;/code&gt; didn’t respect the provided git branch.&lt;/p&gt;
&lt;p&gt;There was a PR &lt;a href=&quot;https://github.com/nvim-neorocks/rocks-git.nvim/pull/29&quot;&gt;that resolved this issue&lt;/a&gt; while I was migrating.
It does sound suspiciously similar to the issue with the tree-sitter grammars failing to install but I haven’t explored that further.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Should-you-use-rocksnvim&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Should-you-use-rocksnvim&quot; class=&quot;heading-ref&quot;&gt;Should you use &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I had issues while migrating my config over to &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt;, with rough edges and missing features.
For instance, I miss the install speed of &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; and &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;’s excellent dashboard.&lt;/p&gt;
&lt;p&gt;Yet I’ll stay with &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; as it deserves props for tackling the huge task of cleaning up dependency management in Neovim and for giving us access to the broader Lua landscape with &lt;a href=&quot;https://luarocks.org/&quot;&gt;luarocks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It may be too bleeding edge for some people; but I think more Neovim users and plugin authors should take note of &lt;a href=&quot;https://github.com/nvim-neorocks/rocks.nvim&quot;&gt;rocks.nvim&lt;/a&gt; and give it a try.
I’d like it if a more sane approach to package management become more popular in the Neovim community.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Autocomplete with nvim-cmp</title><id>http://jonashietala.se/blog/2024/05/26/autocomplete_with_nvim-cmp/index.html</id><updated>2026-04-27T10:59:37+00:00</updated><link href="https://www.jonashietala.se/blog/2024/05/26/autocomplete_with_nvim-cmp" rel="alternate"/><published>2024-05-26T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_tags.png&quot;&gt;
&lt;figcaption&gt;Autocomplete tags in the frontmatter.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Autocompletion is an absurdly powerful feature that I—and I must assume most programmers—use all the time.
It’s not as crucial for writing blog posts as when you’re coding but it’s still easy to come up with examples of how autocomplete would help.
For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Complete frontmatter metadata&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;Lua&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Neovim&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;series&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;extending_neovim_for_my_blog&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s pretty hard to remember &lt;a href=&quot;/blog/tags&quot;&gt;all the tags&lt;/a&gt; I have on the blog.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Links to posts&lt;/p&gt;
&lt;p&gt;You know, typing out &lt;a href=&quot;/blog/2024/02/17/how_i_did_the_layout_for_my_self-published_book&quot;&gt;&lt;code&gt;/blog/2024/02/17/how_i_did_the_layout_for_my_self-published_book&lt;/code&gt;&lt;/a&gt; correctly from memory is pretty much impossible.
Instead I opened the post in the browser, copied the url, removed the host prefix, and then pasted it…
Which is incredibly &lt;mark&gt;slow and annoying&lt;/mark&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Image links&lt;/p&gt;
&lt;p&gt;I often copy an image to the site’s image folder and when I want to insert a link to the image I’ve forgotten the file name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reference link definitions&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://djot.net/&quot;&gt;Djot&lt;/a&gt; (and Markdown) I prefer reference link definitions for my links:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;Here&amp;#39;s &lt;span class=&quot;markup&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;a link&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;markup link label&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup link url&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;markup link label&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation special&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;markup link url&quot;&gt;/uses&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It would be pretty nice to autocomplete the &lt;code&gt;[uses]&lt;/code&gt; reference, like some Markdown LSP servers do.
Or maybe the reverse; if I’ve written &lt;code&gt;[a link][uses]&lt;/code&gt; already but haven’t created the reference link definition for it, we could autocomplete that.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt; is my plugin of choice for autocompletion that supports different sources such as LSP, snippets, spell corrections, math calculations, and more.
Let’s see how to make our own source for &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’ve probably made some mistakes in this post or forgotten something.
Check &lt;a href=&quot;https://github.com/treeman/dotfiles/tree/master/.config/nvim&quot;&gt;my Neovim config&lt;/a&gt; if you see something fishy.&lt;/p&gt;
&lt;section id=&quot;A-basic-completion-source&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#A-basic-completion-source&quot; class=&quot;heading-ref&quot;&gt;A basic completion source&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Creating a custom source for &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt; was described well in &lt;code&gt;:help cmp-develop&lt;/code&gt;.
This is a minimal source that allows you to complete path-like items:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; source &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function scope lua&quot;&gt;source:&lt;/span&gt;&lt;span class=&quot;entity name function lua&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;params, callback&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; There&amp;#39;s also the `cursor_after_line`, `cursor_line`, and a `cursor` fields on `context`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; cursor_before_line &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; params.context.cursor_before_line
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Only complete if there&amp;#39;s a `/` anywhere before the cursor.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; cursor_before_line:sub(&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { label &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/one&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { label &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/two&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; `callback` should always be called.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  callback(items)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Trigger completion (i.e. open up cmp) on these characters.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We can also trigger it manually, see `:help cmp.mapping.complete`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function scope lua&quot;&gt;source:&lt;/span&gt;&lt;span class=&quot;entity name function lua&quot;&gt;get_trigger_characters&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Don&amp;#39;t forget to register your new source to cmp.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;cmp&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).register_source(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, source)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You also need to register the source when you setup cmp:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;cmp&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  sources &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      name &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; `group_index` groups several sources,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; and if any completion item for that index is found
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; all sources with a lower index will be ignored.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      group_index &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Assuming you’ve got &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt; setup correctly, our completion should show up:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/one_two_cmp.png&quot;&gt;
&lt;/figure&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I used &lt;a href=&quot;https://github.com/onsails/lspkind.nvim&quot;&gt;lspkind.nvim&lt;/a&gt; to display the &lt;code&gt;[BLOG]&lt;/code&gt; label and type information.&lt;/p&gt;
&lt;p&gt;You configure it like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;cmp&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  formatting &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    format &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;lspkind&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).cmp_format({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      mode &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;symbol_text&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      menu &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        blog &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[BLOG]&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;section id=&quot;Availability&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Availability&quot; class=&quot;heading-ref&quot;&gt;Availability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It might be a good idea to implement the &lt;code&gt;is_available&lt;/code&gt; function that only activates autocompletion in certain context:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function scope lua&quot;&gt;source:&lt;/span&gt;&lt;span class=&quot;entity name function lua&quot;&gt;is_available&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Only returns `true` if the buffer is a markup file inside my blog directory.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; vim.b[&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;].blog_file
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;vim.b[0].blog_file&lt;/code&gt; is set by Buf autocommand &lt;a href=&quot;/blog/2024/05/02/customizing_neovim#Initial-setup&quot;&gt;from the initial setup&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;autocmd({ &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufRead&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufNewFile&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  pattern &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; autocmd_pattern,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; blog_group,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(opts)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Mark the buffer as a &amp;quot;blog file&amp;quot; buffer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    vim.b[&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;].blog_file &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Formatting-entries&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Formatting-entries&quot; class=&quot;heading-ref&quot;&gt;Formatting entries&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt; doesn’t seem to give as much control over how to display entries as &lt;a href=&quot;/blog/2024/05/08/browse_posts_with_telescopenvim#Formatting-entries&quot;&gt;telescope does&lt;/a&gt; it’s possible to customize it a little.
In particular I’d like to display the entry’s type and mark that it comes from my blog integration (see the image above).&lt;/p&gt;
&lt;section id=&quot;Completion-item-kinds&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Completion-item-kinds&quot; class=&quot;heading-ref&quot;&gt;Completion item kinds&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Something that pops up in &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt;’s source code and help is an “item kind”.&lt;/p&gt;
&lt;p&gt;A “kind” simply describes what type a completion item is.
&lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt; follows the &lt;a href=&quot;https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/&quot;&gt;LSP specification&lt;/a&gt; that includes kinds such as &lt;code&gt;Class&lt;/code&gt;, &lt;code&gt;Constant&lt;/code&gt;, and the default &lt;code&gt;Text&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s how to specify a kind other than &lt;code&gt;Text&lt;/code&gt; for an item:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    label &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/one&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    kind &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;cmp.types.lsp&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).CompletionItemKind.File,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Kinds aren’t anything revolutionary but I think it helps separate different completion types from each other in certain circumstances.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/cmp_kind_completion.png&quot;&gt;
&lt;figcaption&gt;Displaying different kinds with &lt;a href=&quot;https://github.com/onsails/lspkind.nvim&quot;&gt;lspkind.nvim&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The problem is that LSP kinds are focused on code and doesn’t support the kinds I’d like—such as &lt;code&gt;Post&lt;/code&gt;, &lt;code&gt;Draft&lt;/code&gt;, and &lt;code&gt;Standalone&lt;/code&gt;.
To display our own custom types we need to do a little more work.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Custom-format&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Custom-format&quot; class=&quot;heading-ref&quot;&gt;Custom format&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Instead of relying on &lt;a href=&quot;https://github.com/onsails/lspkind.nvim&quot;&gt;lspkind.nvim&lt;/a&gt; let’s use our own format function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;cmp.setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  formatting &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    format &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry, vim_item)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; TODO customize `vim_item` before returning it
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; vim_item
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I like &lt;a href=&quot;https://github.com/onsails/lspkind.nvim&quot;&gt;lspkind.nvim&lt;/a&gt; and I want to use it for everything other than the blog, let’s make it the default:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;make_format&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; lspkind_format &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;lspkind&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).cmp_format({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    mode &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;symbol_text&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ellipsis_char &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;…&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    menu &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      spell &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[SPELL]&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      async_path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[PATH]&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Other sources here...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry, vim_item)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; entry.source.name &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; blog_format(entry, vim_item)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Use `lspkind` formatting as a fallback.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; lspkind_format(entry, vim_item)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Remember to update `cmp.setup`:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;format &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; make_format()
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For the actual formatting &lt;code&gt;vim_item&lt;/code&gt; supports two extra fields that we can customize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kind&lt;/code&gt; holds the type information (the 2nd column).
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;menu&lt;/code&gt; holds the source information (the 3rd column).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;blog_format&lt;/code&gt; might look like this to add type and source information:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; The symols are from Nerd Fonts but won&amp;#39;t show up
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; in the blog properly.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; blog_types &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Post &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { symbol &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;󱚌&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Tag &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { symbol &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;󰓹&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Series &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { symbol &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; etc
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; blog_format &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry, vim_item)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry.completion_item.type
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  vim_item.kind &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; blog_types[type].symbol &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; type
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  vim_item.menu &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[BLOG]&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; vim_item
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also need to add the &lt;code&gt;type&lt;/code&gt; field to our completion items:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  { label &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/one&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Post&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this we can display our custom types in the same way as &lt;a href=&quot;https://github.com/onsails/lspkind.nvim&quot;&gt;lspkind.nvim&lt;/a&gt; does it:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_types.png&quot;&gt;
&lt;figcaption&gt;Displaying our own custom types.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I arrived here by examining the source code of &lt;a href=&quot;https://github.com/onsails/lspkind.nvim&quot;&gt;lspkind.nvim&lt;/a&gt;.
With a Lua LSP server that’s only a quick &lt;code&gt;goto definition&lt;/code&gt; away.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Complete-hidden-text&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Complete-hidden-text&quot; class=&quot;heading-ref&quot;&gt;Complete hidden text&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One cool thing with &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; was the ability to filter on hidden text.
In the &lt;a href=&quot;/blog/2024/05/08/browse_posts_with_telescopenvim#Structured-content&quot;&gt;post finder&lt;/a&gt; we developed we could search for post tags, but only display the post title.
We can do the same with &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt;, where we’ll display one thing, filter against something else, and insert a third piece of text.&lt;/p&gt;
&lt;p&gt;All we need to do is add some extra fields to the completion items:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Text to be displayed in the completion menu.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    label &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Rewriting my Neovim config in Lua&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Text to insert.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    insertText &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/blog/2023/10/01/rewriting_my_neovim_config_in_lua/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Text to filter against, works like `ordinal` for telescope.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    filterText &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/blog/2023/10/01/rewriting_my_neovim_config_in_lua/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;|&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Rewriting my Neovim config in Lua&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this example we display the post title, insert the url to the post, and filters against both the title and the path.&lt;/p&gt;
&lt;p&gt;It’s not as powerful as &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; where we could treat its equivalence to &lt;code&gt;filterText&lt;/code&gt; as &lt;a href=&quot;/blog/2024/05/08/browse_posts_with_telescopenvim#Structured-content&quot;&gt;structured data&lt;/a&gt;.
I don’t think it’s a big deal because with autocomplete you’re more likely to want &lt;code&gt;insertText&lt;/code&gt; to match what you’re typing, so a mini-language &lt;a href=&quot;/blog/2024/05/08/browse_posts_with_telescopenvim#Prompt-syntax&quot;&gt;like we created for telescope&lt;/a&gt; isn’t as practical.&lt;/p&gt;
&lt;p&gt;The most advanced &lt;code&gt;filterText&lt;/code&gt; I use is exactly this example: a combination of the url and the title.
Otherwise I don’t use &lt;code&gt;insertText&lt;/code&gt; or &lt;code&gt;filterText&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;What-to-complete-where&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#What-to-complete-where&quot; class=&quot;heading-ref&quot;&gt;What to complete where?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With &lt;code&gt;source:complete&lt;/code&gt; &lt;a href=&quot;#A-basic-completion-source&quot;&gt;we already have the tools&lt;/a&gt; we need to autocomplete whatever we want.&lt;/p&gt;
&lt;p&gt;The completion part of the integration is the section I’ve had to tweak the most and it has slowly grown more complex.&lt;/p&gt;
&lt;p&gt;It’s actually pretty hard to make an exhaustive autocomplete system.
You’d have to have a parser that’s capable of parsing incomplete statements.
Maybe something like &lt;a href=&quot;/blog/2024/03/19/lets_create_a_tree-sitter_grammar&quot;&gt;a Tree-sitter grammar&lt;/a&gt;, although the &lt;a href=&quot;https://codeberg.org/treeman/tree-sitter-djot&quot;&gt;one I created for Djot&lt;/a&gt; doesn’t mark broken things so it’s useless for this purpose (it marks a paragraph with a single &lt;code&gt;_&lt;/code&gt; as text instead of broken emphasis for example).&lt;/p&gt;
&lt;p&gt;I’ve therefore been relying on regexes on &lt;code&gt;cursor_before_line&lt;/code&gt; to select what to complete.
You could probably design a more powerful solution but this simple approach has served me well so far.&lt;/p&gt;
&lt;section id=&quot;Completion-logic&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Completion-logic&quot; class=&quot;heading-ref&quot;&gt;Completion logic&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here’s one of first versions of &lt;code&gt;source:complete&lt;/code&gt; to give you an idea on how you might choose what to complete:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Expand images separately because I only ever use it in a -- `![](/url)`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; context and not mixing with other urls gives a more pleasant experience.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(cursor_before_line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;!%[%]%([^%)]*$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; items = ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Expand inline links, e.g. `[txt](/`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(cursor_before_line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%]%(/[^%)]*$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; items = ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Expanding headings in inline links, e.g. `[txt](#`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(cursor_before_line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%]%(#[^%)]*$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; items = ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Expand links in link ref definitions, e.g. `[label]: `
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(cursor_before_line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;^%[.+%]:%s+&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; items = ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Expanding links in ref defs, e.g. `[label]: #`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(cursor_before_line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;^%[.+%]:%s+#&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; items = ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Expand url definition tags in `[text][tag]`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(cursor_before_line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%[[^%]]+%]%[[^%]]*$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; items = ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Expand url definition tags in `[tag][]`, simplified to after a `[`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; If at the beginning of the line, we should complete broken link tags to..
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(cursor_before_line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%[[^%]]*$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; items = ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; More cases here...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;callback(items)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;As the completion logic grew more complex, I moved it out from Neovim to the backend.
It was easier to setup completion details for individual items that way, and now I only rely on a single 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Complete&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; message that I pipe directly back to &lt;code&gt;cmp&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function scope lua&quot;&gt;source:&lt;/span&gt;&lt;span class=&quot;entity name function lua&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;params, callback&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  server.call({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    id &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Complete&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.expand(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%:p&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }, &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(reply)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Items is a list where items have `label`,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; `insertText`, and `filterText`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; like we manually coded before.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    callback(reply.completion_items)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/jonashietala/src/branch/master/src/server/complete.rs&quot;&gt;I still rely&lt;/a&gt; on the regex based approach though.&lt;/p&gt;
&lt;p&gt;I’ll revisit how the backend communication works in a future post.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Anatomy-of-a-regex&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Anatomy-of-a-regex&quot; class=&quot;heading-ref&quot;&gt;Anatomy of a regex&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Don’t be too scared of the regexes.
They’re hard to read if you’re unfamiliar, but not &lt;em&gt;too&lt;/em&gt; bad once you use them a bit.&lt;/p&gt;
&lt;p&gt;For example, here’s how the regex matches an image url with the text &lt;code&gt;![](/path&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;!           !
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;%[          [   `%` escapes special characters
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;%]          ]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;%(          (
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[           all characters
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  ^           not equal to
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  %)          )
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;]*            0 or more times
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;$           end of string
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s important to include the end of string, so that we don’t autocomplete images after the image has ended:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;![](/img) Trailing path /
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        ^
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        Don&apos;t autocomplete image here
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;[^%)]*&lt;/code&gt; part allows the completion to match further into the path:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;![](/im
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      ^
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      We&apos;re not done yet
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;Astute regex practitioners might notice that the image regex only matches &lt;code&gt;![](/path)&lt;/code&gt;, and not &lt;code&gt;![img text](/path)&lt;/code&gt;.
To fix it maybe we could use a regex like &lt;code&gt;!%[[^%]]*%]%([^%)]*$&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But we’re still not handling newlines in the image text!&lt;/p&gt;
&lt;p&gt;Yes, the correct solution is more complex than regex matching against &lt;code&gt;cursor_before_line&lt;/code&gt;.
That’s an exercise for the concerned reader to implement.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Item-documentation&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Item-documentation&quot; class=&quot;heading-ref&quot;&gt;Item documentation&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_header_ref_post.png&quot;&gt;
&lt;figcaption&gt;Completion of a heading references for a url, showing the heading context.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Another feature is the “documentation window” which is an extra window with information about the entry you’re currently selecting.
To set it up all we need to do is implement &lt;code&gt;source:resolve&lt;/code&gt; and set &lt;code&gt;item.documentation&lt;/code&gt;, for example like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function scope lua&quot;&gt;source:&lt;/span&gt;&lt;span class=&quot;entity name function lua&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;item, callback&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We should generate `lines` depending on the item.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; lines &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;`Rewriting my Neovim config in Lua`&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;2023-10-01&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;*Neovim*, *Lua*&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;---&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Post content here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; lines &lt;span class=&quot;keyword operator lua&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;#&lt;/span&gt;lines &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    item.documentation &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      kind &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;markdown&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      value &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.join(lines, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape lua&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape lua&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback(item)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We could’ve set &lt;code&gt;item.description&lt;/code&gt; immediately but &lt;code&gt;source:resolve&lt;/code&gt; is preferable as it’s only called when we select the item, making it the better choice if we want to do some heavier operations (such as reading from a file).&lt;/p&gt;
&lt;p&gt;Speaking of reading from a file, here’s a function that lets you read a range of lines from a file:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Collect the lines into `res` instead of returning it,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; to make it easier to insert lines before the file content.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;read_lines&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;file, start_row, end_row, res&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; linenum &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;keyword control lua&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;io.lines&lt;/span&gt;(file) &lt;span class=&quot;keyword control lua&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; linenum &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;gt;=&lt;/span&gt; start_row &lt;span class=&quot;keyword operator lua&quot;&gt;and&lt;/span&gt; linenum &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;=&lt;/span&gt; end_row &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(res, line)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    linenum &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; linenum &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; linenum &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;gt;&lt;/span&gt; end_row &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;break&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s used like this to produce a documentation for a heading item from another file (preferring &lt;code&gt;nvim_buf_get_lines&lt;/code&gt; for headings in the current buffer):&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;_heading_docs&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;heading&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; If there&amp;#39;s a heading path, then the item is pointing to a heading in another file.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; heading.context.path &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Uses markdown to make the url bold and adds a separator before the heading context.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; res &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;*&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; heading.context.url &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;*&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;---&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Read the heading and the 10 following lines.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    read_lines(heading.context.path, heading.context.start_row, heading.context.end_row &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;10&lt;/span&gt;, res)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; res
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; If we don&amp;#39;t have a heading then heading points to the same file.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We can use the buffer `0` to read lines from the current buffer.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; vim.api.nvim_buf_get_lines(
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      heading.context.start_row,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      heading.context.end_row &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;10&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    )
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To display post bodies we also need to skip the frontmatter.
The frontmatter for my posts are delimited by &lt;code&gt;---&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;attribute&quot;&gt;toml&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;title = &amp;quot;My post title&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;tags = [&amp;quot;Lua&amp;quot;, &amp;quot;Neovim&amp;quot;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Post body here&lt;span class=&quot;string special&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can do this by counting how many &lt;code&gt;---&lt;/code&gt; we see, and only collecting lines after we’ve seen two of them:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Collect `limit` lines from `file` into `res`, skipping the post frontmatter.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;read_post_body&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;file, limit, res&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; count &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; frontmatter_delimiters &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;keyword control lua&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;io.lines&lt;/span&gt;(file) &lt;span class=&quot;keyword control lua&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; frontmatter_delimiters &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(res, line)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      count &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; count &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; count &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;gt;&lt;/span&gt; limit &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;break&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;^%-%-%-&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      frontmatter_delimiters &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; frontmatter_delimiters &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;_post_docs&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; I add more things such as tags and series
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; but I shortened the code for this example.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; res &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;`&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; post.title &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;`&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;---&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  read_post_body(post.path, &lt;span class=&quot;constant numeric lua&quot;&gt;20&lt;/span&gt;, res)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; res
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;The documentation window only supports &lt;code&gt;markdown&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; types.
It’s unfortunate but &lt;a href=&quot;https://djot.net/&quot;&gt;Djot&lt;/a&gt; is similar enough to Markdown that I can live with treating it as Markdown.
I tried to wrap the markup in code blocks, but for some reason that removed the syntax highlight.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Sorting&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Sorting&quot; class=&quot;heading-ref&quot;&gt;Sorting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt; you get full control over the sorting of items.
Sorting is done with standard comparison functions (e.g. &lt;code&gt;entry1.modified &amp;gt; entry2.modified&lt;/code&gt;) that you can chain.
We can add our own comparator to &lt;code&gt;cmp.setup&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;cmp.setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  sorting &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    comparators &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; With cmp you chain comparators.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      cmp.config.compare.offset,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.exact,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.score,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.recently_used,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.locality,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; I added my comparator here.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      blog_compare,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.kind,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.sort_text,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.length,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      cmp.config.compare.order,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;blog_compare&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;entry1, entry2&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; TODO
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;nil&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first thing I’d like to do is sort different completion types, similar to &lt;code&gt;cmp.config.compare.kind&lt;/code&gt; but for the custom blog types:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; blog_types &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  BrokenLink &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { rank &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;, symbol &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;󰌺&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  LinkDef &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { rank &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;, symbol &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;󰌹&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; etc
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;blog_compare&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;entry1, entry2&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Only sort blog entries.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; entry1.source.name &lt;span class=&quot;keyword operator lua&quot;&gt;~=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;or&lt;/span&gt; entry2.source.name &lt;span class=&quot;keyword operator lua&quot;&gt;~=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;nil&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; item1 &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry1.completion_item
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; item2 &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry2.completion_item
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; rank1 &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; blog_types[item1.type].rank
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; rank2 &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; blog_types[item2.type].rank
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; rank1 &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;&lt;/span&gt; rank2 &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;elseif&lt;/span&gt; rank1 &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;gt;&lt;/span&gt; rank2 &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; The types are the same, `nil` doesn&amp;#39;t imply a sort order between them.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;nil&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At the end of &lt;code&gt;blog_compare&lt;/code&gt; we can add our type specific comparisons.
For example, we can sort images by the modified timestamp so that the newest image comes first, making it easy to insert new images:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; item1.type &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Img&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Sort images by modification time.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; item1.modified &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;gt;&lt;/span&gt; item2.modified
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; More type specific sorting cases here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;nil&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;/section&gt;
&lt;section id=&quot;Wrap-up&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Wrap-up&quot; class=&quot;heading-ref&quot;&gt;Wrap-up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With this we’ve created our own completion source for &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt;.
We’ve &lt;a href=&quot;#Formatting-entries&quot;&gt;tweaked the display&lt;/a&gt;, separated the &lt;a href=&quot;#Complete-hidden-text&quot;&gt;insert and filter text&lt;/a&gt;, added &lt;a href=&quot;#Item-documentation&quot;&gt;item documentation&lt;/a&gt;, and &lt;a href=&quot;#Sorting&quot;&gt;customized the sorting&lt;/a&gt;.
The completion has been extremely helpful for me and I’ll end this post with a gallery of the completion in action:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/extend_blog/complete_gallery.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_gallery.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/extend_blog/complete_img.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_img.png&quot;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_series.png&quot;&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/extend_blog/complete_heading.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_heading.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/extend_blog/complete_tag2.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/complete_tag2.png&quot;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Check out &lt;a href=&quot;https://github.com/treeman/dotfiles/tree/master/.config/nvim&quot;&gt;my Neovim config&lt;/a&gt; and &lt;a href=&quot;https://codeberg.org/treeman/jonashietala/src/branch/master/src/server/complete.rs&quot;&gt;the site source&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Browse posts with telescope.nvim</title><id>http://jonashietala.se/blog/2024/05/08/browse_posts_with_telescopenvim/index.html</id><updated>2026-04-27T10:06:36+00:00</updated><link href="https://www.jonashietala.se/blog/2024/05/08/browse_posts_with_telescopenvim" rel="alternate"/><published>2024-05-08T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve used &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt;&apos;s find files with 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.builtin&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_files&lt;/code&gt; for quite some time.
I use find files together with it’s cousin &lt;code&gt;.oldfiles&lt;/code&gt; (find recently opened files) all the time for finding source code files, blog posts, and more.&lt;/p&gt;
&lt;p&gt;But it’s naturally restricted to operate on only filenames and you can make telescope richer by operating on structured data.&lt;/p&gt;
&lt;p&gt;So let’s move away from using the files finder to find posts:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/find_files.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;To a custom posts picker that display posts in a neater way and allows us to filter using tags or other metadata:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/find_posts.png&quot;&gt;
&lt;/figure&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I use the &lt;code&gt;filename_first&lt;/code&gt; option to display filenames before the directory in &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; files finders:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  defaults &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    path_display &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;filename_first&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;section id=&quot;The-simplest-picker&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-simplest-picker&quot; class=&quot;heading-ref&quot;&gt;The simplest picker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s fairly easy to create a new picker for &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt;.
In it’s simplest form, all you need to do is provide a list of items:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; pickers &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.pickers&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; finders &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.finders&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pickers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  .new(opts, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    finder &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; finders.new_table({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      results &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;One&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Two&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Three&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  :find()
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;How do I know this?
Because I watched &lt;a href=&quot;https://www.youtube.com/watch?v=HXABdG3xJW4&quot;&gt;Developing a Neovim Docker Plugin from Scratch&lt;/a&gt;.
It does a way better job walking you through a telescope plugin than I could ever do.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Then we need to call the above code somehow, for example by wrapping it in a function and add a keymap to it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; map &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.keymap.set
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;gd&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.telescope&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_draft, { desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Find blog draft&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;gp&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.telescope&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_post, { desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Find blog post&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Structured-content&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Structured-content&quot; class=&quot;heading-ref&quot;&gt;Structured content&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To make our simple picker handle structured content we need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Convert &lt;code&gt;results&lt;/code&gt; to a list of tables with the info we have.
&lt;/li&gt;
&lt;li&gt;
Specify an &lt;code&gt;entry_marker&lt;/code&gt; function.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A rewrite of &lt;code&gt;finder&lt;/code&gt; in our simple picker might look like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;finder &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; finders.new_table({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; 1. Structured data inside `results`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  results &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    { title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;One&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Tag1, Tag2&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;posts/2024-01-01-one.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    { title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Two&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Tag2&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;posts/2024-02-02-two.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; 2. A function that converts a result entry to an entry telescope understands.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  entry_maker &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Display the post title instead of the path in the list.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      display &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry.title,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Allow us to filter against the title and tags (typing `Tag1` finds the &amp;quot;One&amp;quot; post).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      ordinal &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry.title &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; entry.tags,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We could also save the whole entry for future usage, if we need it.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      value &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}),
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this the finder displays the title of the post rather than the file path, and we can search for a post using the title and its tags.&lt;/p&gt;
&lt;p&gt;It’s easy to add more metadata to &lt;code&gt;ordinal&lt;/code&gt; and it’ll mostly work, but the matching is crude and it can easily misfire depending on your use-case.&lt;/p&gt;
&lt;p&gt;Because the way fuzzy matching works, if I type &lt;strong&gt;lua&lt;/strong&gt; with the hope of listing all posts tagged lua, it will also match any post that has the letters &lt;strong&gt;l&lt;/strong&gt; &lt;strong&gt;u&lt;/strong&gt; &lt;strong&gt;a&lt;/strong&gt; in that order, which is currently almost 40 of them:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/lua_match_voron.png&quot;&gt;
&lt;figcaption&gt;Prompting for &lt;code&gt;lua&lt;/code&gt; matches too many posts.&lt;br&gt;
Here I’ve also added the post date to &lt;code&gt;display&lt;/code&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Clearly, there’s room for improvement.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Structured-filtering-and-sorting&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Structured-filtering-and-sorting&quot; class=&quot;heading-ref&quot;&gt;Structured filtering and sorting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Turns out that &lt;code&gt;ordinal&lt;/code&gt; can also be a table, and you can provide your own &lt;code&gt;sorter&lt;/code&gt; that operates on the ordinal to sort and filter.&lt;/p&gt;
&lt;p&gt;This is the basic setup:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;pickers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;.new(opts, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  finder &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; finders.new_table({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    results &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; `tags` is now a list.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      { title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;One&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Tag1&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Tag2&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;posts/2024-01-01-one.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Two&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Tag2&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;posts/2024-02-02-two.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    entry_maker &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        display &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry.title,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; `ordinal` is now a table containing all the entry info specified in `results`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        ordinal &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; This is the important `sorter` function.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  sorter &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; post_sorter(opts),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:find()
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;post_sorter&lt;/code&gt; should return a new &lt;code&gt;Sorter&lt;/code&gt; that describes the sorting behavior:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;post_sorter&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  opts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; opts &lt;span class=&quot;keyword operator lua&quot;&gt;or&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We can use `fzy_sorter` for the actual fuzzy matching.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; fzy_sorter &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; sorters.get_fzy_sorter(opts)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; sorters.Sorter:new({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Allow us to filter entries as well as sorting them.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    discard &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    scoring_function &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(_, prompt, entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; This mimics a standard fuzzy sorting on the entry title.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; fzy_sorter:scoring_function(prompt, entry.title)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We could also specify a highlighter. The highlighter works fine in this case,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; but if we modify `scoring_function` we have to modify this too.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; I admit, I currently don&amp;#39;t use a highlighter for my posts finder.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    highlighter &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; fzy_sorter.highlighter,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s some ceremony here that I hope is clear enough.
The important thing here is the &lt;code&gt;scoring_function&lt;/code&gt; that we’ll need to adjust.&lt;/p&gt;
&lt;p&gt;First, the input arguments to &lt;code&gt;scoring_function&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The first argument seems to be ignored even in Telescope’s own standard sorters, so I ignore it as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;prompt&lt;/code&gt; is the user input to the Telescope prompt as a string.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;entry&lt;/code&gt; is the ordinal entry that &lt;code&gt;entry_maker&lt;/code&gt; returns.&lt;/p&gt;
&lt;p&gt;For instance, in our example &lt;code&gt;entry&lt;/code&gt; could be this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;{ title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Two&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Tag2&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;posts/2024-02-02-two.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What &lt;code&gt;scoring_function&lt;/code&gt; should do is return a single numeric value signifying how close &lt;code&gt;ordinal&lt;/code&gt; is to &lt;code&gt;prompt&lt;/code&gt;, where higher means a better match.
Because we defined 
&lt;code class=&quot;highlight lua&quot;&gt;discard &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;&lt;/code&gt; if we return a value less than 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;&lt;/code&gt;, the entry will get removed (filtered).&lt;/p&gt;
&lt;p&gt;At first I thought this was a weird way of creating a sorting function.
I had expected a comparison function like 
&lt;code class=&quot;highlight lua&quot;&gt;cmp(left, right)&lt;/code&gt; but after having played with it a little it seems pretty clever.&lt;/p&gt;
&lt;section id=&quot;Sorter-requirements&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Sorter-requirements&quot; class=&quot;heading-ref&quot;&gt;Sorter requirements&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before implementing &lt;code&gt;scoring_function&lt;/code&gt;, let’s take a step back and figure out what behavior we want.
You could go nuts with advanced features such as boolean operators, set comparisons, and similar.
While cool, I don’t think it’s worth implementing as my requirements are fairly simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fuzzy find on title, tags, and series.&lt;/p&gt;
&lt;p&gt;I don’t want to require a perfect match on tags, requiring me to fully type out for example &lt;a href=&quot;/blog/tags/experimental_gameplay_project&quot;&gt;Experimental Gameplay Project&lt;/a&gt; would be &lt;em&gt;quite&lt;/em&gt; annoying.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Explicitly filter posts by series and tags.&lt;/p&gt;
&lt;p&gt;It’s neat if you can type some text and it filters for series &lt;em&gt;or&lt;/em&gt; post title, but in practice I never really want that.
If I want to filter against the post series, I want to be explicit about it and the same holds for tags.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Filter posts containing &lt;code&gt;tag1&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;tag2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I contemplated searching for &lt;code&gt;tag1&lt;/code&gt; &lt;em&gt;or&lt;/em&gt; &lt;code&gt;tag2&lt;/code&gt;, but what I want is to reduce the number of matches as I add more information, not increase them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Include published date in ordering.&lt;/p&gt;
&lt;p&gt;At a base level I want to see newer posts before older ones.
This is especially true when I first open telescope without prompting anything, then I want to see an ordered lists of all posts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Prompt-syntax&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Prompt-syntax&quot; class=&quot;heading-ref&quot;&gt;Prompt syntax&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because I want to be explicit we need some syntax to separate text we want to match against post tags, series, and title.
Simplicity is nice, and a simple solution is to prefix tags with &lt;code&gt;@&lt;/code&gt; and prefix series with &lt;code&gt;#&lt;/code&gt;, separated by spaces.
I usually find that an example is worth a 1000 words, so here are some examples to shave down the precious words count:&lt;/p&gt;
&lt;ol type=&quot;i&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;@rust gleam&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Require a post tag matching &lt;code&gt;rust&lt;/code&gt; and post title matching &lt;code&gt;gleam&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;@3d @hex&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Require a post tag matching &lt;code&gt;3d&lt;/code&gt; and one matching &lt;code&gt;hex&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;#34&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Require a post series matching &lt;code&gt;34&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;build # start&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Require a post with a series and post title matching &lt;code&gt;build start&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The code that converts a prompt into parts is conceptually simple: split the prompt into words and categorize them depending starting character.
This is what I use:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;split_prompt&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; series &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Iterates over all non-space substrings.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; `prompt:gmatch` is syntax sugar for `string.gmatch(prompt, ..)`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;for&lt;/span&gt; word &lt;span class=&quot;keyword control lua&quot;&gt;in&lt;/span&gt; prompt:gmatch(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;([^%s]+)&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Use `sub(1, 1)` to get the first character.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; It works with empty strings too!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; fst &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; word:sub(&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; fst &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;@&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Use `sub(2)` to skip the `@`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(tags, word:sub(&lt;span class=&quot;constant numeric lua&quot;&gt;2&lt;/span&gt;))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;elseif&lt;/span&gt; fst &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;#&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(series, word:sub(&lt;span class=&quot;constant numeric lua&quot;&gt;2&lt;/span&gt;))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(title, word)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; tags,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    series &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; series,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Combine non-tagged elements into a string.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Could&amp;#39;ve be done outside this function but it&amp;#39;ll always be done
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; so I thought it would be easier to join here.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.join(title, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m a bit of a Lua noob, so there may be better solutions.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Implementing-scoring_function&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Implementing-scoring_function&quot; class=&quot;heading-ref&quot;&gt;Implementing &lt;code&gt;scoring_function&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With a plan in place, let’s go back to try to realize it.
The basic idea is to match against series, tags, and title separately and add their scores at the end:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;scoring_function &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(_, prompt, entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  prompt &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; split_prompt(prompt)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; series_score &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; score_element(prompt.series, entry.series, fzy_sorter)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; series_score &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; tags_score &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; score_element(prompt.tags, entry.tags, fzy_sorter)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; tags_score &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; title_score &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; fzy_sorter:scoring_function(prompt.title, entry.title)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; title_score &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; series_score &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; tags_score &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; title_score
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Remember that a return value of 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;&lt;/code&gt; filters the entry, so we make sure to check that for each part.
This is already how &lt;code&gt;fzy_sorter:scoring_function&lt;/code&gt; works and it will either return 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;&lt;/code&gt; for entries we should remove and a value in 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;&lt;/code&gt; otherwise.
Because the matching of tags and series is so similar, I introduced the &lt;code&gt;score_element&lt;/code&gt; helper function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Match the list `prompt_elements` against `entry_element`, either a list or a string.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;score_element&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;prompt_elements, entry_element, sorter&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We didn&amp;#39;t prompt for this type, ignore it.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; This is a &amp;quot;is list empty?&amp;quot; check in Lua.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;next&lt;/span&gt;(prompt_elements) &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We prompted for this type, but entry didn&amp;#39;t have it, so remove the entry.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; For example if we prompt for a series, this removes all posts
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; without a series.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;not&lt;/span&gt; entry_element &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Convert multiple entry values to a string like `tag1:tag2`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; entry
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We can use `type()` to dynamically check the type of a variable
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; and act occordingly.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;type&lt;/span&gt;(entry_element) &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;string&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    entry &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry_element
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;type&lt;/span&gt;(entry_element) &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;table&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    entry &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.join(entry_element, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;:&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; total &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; For each prompt element (`tag1`, `tag2`, ...), match against the entry string (`tag1:tag2`).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;for&lt;/span&gt; _, prompt_element &lt;span class=&quot;keyword control lua&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;ipairs&lt;/span&gt;(prompt_elements) &lt;span class=&quot;keyword control lua&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; score &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; sorter:scoring_function(prompt_element, entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Require a match for every element.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; score &lt;span class=&quot;keyword operator lua&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    total &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; total &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; score
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Clamp score to 0..1.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Not strictly needed but it feels neater.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; total &lt;span class=&quot;keyword operator lua&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;#&lt;/span&gt;prompt_elements
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this in place we have a working sorter.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
If we type regular text, then &lt;code&gt;series_score&lt;/code&gt; and &lt;code&gt;tags_score&lt;/code&gt; will be 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;&lt;/code&gt;, practically ignoring them.
&lt;/li&gt;
&lt;li&gt;
A &lt;code&gt;#series_filter&lt;/code&gt; will set 
&lt;code class=&quot;highlight lua&quot;&gt;series_score &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;&lt;/code&gt; unless the post has a matching series, removing the entry.
&lt;/li&gt;
&lt;li&gt;
And typing &lt;code&gt;@tag1 @tag2&lt;/code&gt; will require a match for every tag, otherwise 
&lt;code class=&quot;highlight lua&quot;&gt;tags_score &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;&lt;/code&gt; that again removes the entry.
&lt;/li&gt;
&lt;li&gt;
Adding the fuzzy scores together gives us a pretty good fuzzy matching behavior I feel.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only requirement left is to order posts by date.
It must be done carefully not to override the sort order we get from the fuzzy matching.&lt;/p&gt;
&lt;p&gt;One way to do this is to sort all posts and add a post counter to each entity (so the first post would get 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;&lt;/code&gt; and the last 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;272&lt;/span&gt;&lt;/code&gt;) and then add it to the final score somehow.
This felt a little cumbersome and I wanted to see if I could implement the scoring function without having to sort the entries first.
After all, we already have the date of each post…&lt;/p&gt;
&lt;p&gt;This is possible by placing the post on a timeline between the date of the very first post and today, and then clamping the range to 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt;&lt;/code&gt;.
Something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Date of my first blog post as a number.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; beginning_of_time &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;20090621&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Today&amp;#39;s date as a number.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; today &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;os.date&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%Y%m%d&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; The entry date looks like `2023-01-31`, if we remove `-` it&amp;#39;s formatted like the above.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; entry_date &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.gsub&lt;/span&gt;(entry.date, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;-&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Place the entry date on a 0..1 scale, where 1 is today.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; (`1 -` reverses, otherwise 1 would be the beginning of time).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; date_score &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt; (entry_date &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt; beginning_of_time) &lt;span class=&quot;keyword operator lua&quot;&gt;/&lt;/span&gt; (today &lt;span class=&quot;keyword operator lua&quot;&gt;-&lt;/span&gt; beginning_of_time)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Date sorting is only worth 1/10 of the fuzzy scores.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Why? I dunno, 1 was too much and 1/10 felt good.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; series_score &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; tags_score &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; title_score &lt;span class=&quot;keyword operator lua&quot;&gt;+&lt;/span&gt; date_score &lt;span class=&quot;keyword operator lua&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;10&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Okay, I admit it’s a little hacky;
but it’s a fun one that fulfills my needs.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Formatting-entries&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Formatting-entries&quot; class=&quot;heading-ref&quot;&gt;Formatting entries&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/telescope_display_format.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;It’s possible to customize how &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; displays an entry in the results list,
see &lt;code&gt;:help telescope.pickers.entry_display&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You’ll use &lt;code&gt;entry_display.create()&lt;/code&gt; to create a formatting function that divides the display into columns, then you pass in the columns to produce the line to be displayed.&lt;/p&gt;
&lt;p&gt;This is a basic example that divides the line into two parts; an icon and a title, together with a highlight group to colorize the parts:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; entry_display &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.pickers.entry_display&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;entry_maker &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    display &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; displayer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry_display.create({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        separator &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          { width &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          { remaining &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; displayer({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;󰇷&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TelescopeResultsComment&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        { entry.value.title, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TelescopeResultsNumber&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ..
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;I took the icon from &lt;a href=&quot;https://www.nerdfonts.com/&quot;&gt;Nerd Fonts&lt;/a&gt;, selected using &lt;a href=&quot;https://github.com/2KAbhishek/nerdy.nvim&quot;&gt;nerdy.nvim&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;The display I use to display filetype icon, title, date, tags, and series is a little more complex but the display logic is similar:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; devicons &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-web-devicons&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; telescope_utils &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.utils&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; make_display &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Djot doesn&amp;#39;t have an icon, I just picked something that looked neat.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; ext &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; telescope_utils.file_extension(entry.value.path)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; ext &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ext &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;tcl&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; icon, _ &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; devicons.get_icon_by_filetype(ext)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Tags may be a string or a table, convert it for display purposes.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; tags
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;type&lt;/span&gt;(entry.value.tags) &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;string&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry.value.tags
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;type&lt;/span&gt;(entry.value.tags) &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;table&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    tags &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.join(entry.value.tags, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; series &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry.value.series &lt;span class=&quot;keyword operator lua&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; displayer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry_display.create({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    separator &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    items &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { width &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric lua&quot;&gt;1&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { width &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.len&lt;/span&gt;(entry.value.title) },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { width &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.len&lt;/span&gt;(entry.value.date) },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { width &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.len&lt;/span&gt;(tags) },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      { remaining &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; displayer({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    { icon, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TelescopeResultsComment&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; We can skip highlight groups if we want.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    entry.value.title,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    { entry.value.date, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TelescopeResultsComment&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    { tags, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TelescopeResultsConstant&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    { series, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TelescopeResultsOperator&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since I grouped the display in a function, we need to set that to &lt;code&gt;display&lt;/code&gt; in &lt;code&gt;entry_maker&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;entry_maker &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    display &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; make_display,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I use &lt;a href=&quot;https://github.com/nvim-tree/nvim-web-devicons&quot;&gt;nvim-web-devicons&lt;/a&gt; to map a &lt;a href=&quot;https://www.nerdfonts.com/&quot;&gt;Nerd Nerd Font icon&lt;/a&gt; to a filetype (also used by &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; for the standard file pickers if available).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;File-preview&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#File-preview&quot; class=&quot;heading-ref&quot;&gt;File preview&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the great features of &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; is the very fast preview with syntax highlighting, which we naturally must configure.&lt;/p&gt;
&lt;p&gt;I searched through the telescope help, and found the functions &lt;code&gt;new_buffer_previewer&lt;/code&gt; and &lt;code&gt;buffer_previewer_maker&lt;/code&gt; that allows us to define a previewer for a file:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; previewers &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.previewers&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;finder &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; finders.new_table({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  previewer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; previewers.new_buffer_previewer({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Title isn&amp;#39;t needed.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Post Preview&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    define_preview &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;variable language self lua&quot;&gt;self&lt;/span&gt;, entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Notice `entry.value.path` that uses our catch-all entry value.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      conf.buffer_previewer_maker(entry.value.path, &lt;span class=&quot;variable language self lua&quot;&gt;self&lt;/span&gt;.state.bufnr, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        bufname &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;variable language self lua&quot;&gt;self&lt;/span&gt;.state.bufname,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        winid &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;variable language self lua&quot;&gt;self&lt;/span&gt;.state.winid,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        preview &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; opts.preview,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; The file encoding is needed for proper syntax highlighting.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        file_encoding &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; opts.file_encoding,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m not sure if there’s a less verbose way to define a file previewer, as the only things I configured here are the title and the &lt;code&gt;entry.value.path&lt;/code&gt; argument to &lt;code&gt;buffer_preview_maker&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Open-the-selected-file&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Open-the-selected-file&quot; class=&quot;heading-ref&quot;&gt;Open the selected file&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We have the display of our &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; picker configured.
Now how do we open the file once we’ve found it?
By default there’s no way of interacting with an entry, we can only look at it.&lt;/p&gt;
&lt;p&gt;Turns out all you need to do is add &lt;code&gt;filename&lt;/code&gt; to &lt;code&gt;entry_maker&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;entry_maker &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(entry)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Make standard action open `entry.path`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    filename &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; entry.path,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;At first I implemented opening manually using &lt;code&gt;attach_mappings&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; actions &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.actions&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;finder &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; finders.new_table({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  attach_mappings &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(prompt_bufnr)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    actions.select_default:replace(&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; selection &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; action_state.get_selected_entry()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      actions.close(prompt_bufnr)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;:e &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; selection.value.path)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above mapping overrides the default selection action (&lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt;) to &lt;code&gt;:edit&lt;/code&gt; &lt;code&gt;value.path&lt;/code&gt; of our selection, which will open the selected file.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Finding-the-post-data-to-populate-the-picker&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Finding-the-post-data-to-populate-the-picker&quot; class=&quot;heading-ref&quot;&gt;Finding the post data to populate the picker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far I’ve only used placeholder data for the posts, but we need to search the file system for the markup files for the posts.&lt;/p&gt;
&lt;p&gt;It’s not as simple as listing files in a directory, we also need to extract post metadata that’s defined in a frontmatter at the beginning of every markup file:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;---toml&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Let&amp;#39;s build a VORON: Noise&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;3D printing&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;VORON&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;series&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;voron_trident&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;---&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How can we do this?&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt; and regex of course!&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/regular_expressions.png&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://xkcd.com/208/&quot;&gt;xkcd 208&lt;/a&gt;
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This time though I have a good reason for choosing an external tool rather than asking the backend server:
I want to be able to find a post the very first thing I do when opening Neovim, and I don’t want to wait on connecting to a backend service, or requiring one running at all times.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I guess this is mostly an excuse to try to do as much as I can in Lua, as I could’ve reused the parser on the backend and treat it as a command-line program like we’ll do with ripgrep.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;The strategy is to use &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt; to match the frontmatter in all posts, extract the metadata using some hacky Lua regex, and combine them into a post struct we can feed into the &lt;a href=&quot;#Structured-content&quot;&gt;finder we developed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here’s one way that uses &lt;a href=&quot;https://github.com/nvim-neotest/nvim-nio&quot;&gt;nvim-nio&lt;/a&gt; and &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt; to find all posts under a path and extract the frontmatter:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; nio &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nio&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.path&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;nio.process.run({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  cmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;rg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  args &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;-NoHU&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;--heading&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape lua&quot;&gt;\\&lt;/span&gt;A&lt;span class=&quot;constant character escape lua&quot;&gt;\\&lt;/span&gt;---&lt;span class=&quot;constant character escape lua&quot;&gt;\\&lt;/span&gt;w*&lt;span class=&quot;constant character escape lua&quot;&gt;\\&lt;/span&gt;n(.+&lt;span class=&quot;constant character escape lua&quot;&gt;\\&lt;/span&gt;n)+^---&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Subpath could be `posts/` or `drafts/`, converted to an absolute path.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    path.blog_path &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; subpath,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which will produce output formatted like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;posts/2016-07-29-slackware_installation_notes.markdown
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;---
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;layout: post
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;title: &quot;Slackware installation notes&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;tags: Slackware
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;---
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;posts/2019-01-25-site_restyle_and_update.markdown
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;---
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;title: &quot;Site restyle and update&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;tags: [&quot;Blog&quot;, &quot;Web Design&quot;]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;---
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;posts/2024-02-27-lets_build_a_voron_more_mods.dj
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;---toml
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;title = &quot;Let&apos;s build a VORON: More mods&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;tags = [&quot;3D printing&quot;, &quot;VORON&quot;]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;series = &quot;voron_trident&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;---
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;My code for splitting the output and extracting the metadata is really gross:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; lines &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.split(output, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape lua&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; posts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; post &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;for&lt;/span&gt; _, line &lt;span class=&quot;keyword control lua&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;ipairs&lt;/span&gt;(lines) &lt;span class=&quot;keyword control lua&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; When a newline is encountered save the post and prepare for the next entry.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; line &lt;span class=&quot;keyword operator lua&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; post.title &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(posts, post)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    post &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Skip `---` markers.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%-%-%-%w*&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Try to extract all key value definitions and store them.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; key, value &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;(%w+)%s*[:=]%s*(.+)&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Strip surrounding quotes.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Do this here because there&amp;#39;s no non-greedy specifier that could be used
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; in the key/value regex above.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      value &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; trim_quotes(value)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Split a sequence.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; seq &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(value, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;^%[(.+)%]$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; seq &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; parts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;for&lt;/span&gt; part &lt;span class=&quot;keyword control lua&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.gmatch&lt;/span&gt;(seq, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%s*([^,]+)&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control lua&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(parts, trim_quotes(part))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        value &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; parts
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      post[key] &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; value
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; If no key value pair is found, then we should be at the beginning with the file path.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      post[&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;path&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; line
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Only posts have a date in the path, not drafts.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; date &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(line, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;posts/(%d%d%d%d%-%d%d%-%d%d)%-&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; date &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        post[&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;date&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; date
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Use the modified timestamp for drafts.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        post[&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;date&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;os.date&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%Y-%m-%d&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, util.file_modified(line))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; If output ends we might have an unsaved post.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; post.title &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support function library lua&quot;&gt;table.insert&lt;/span&gt;(posts, post)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;trim_quotes&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter function lua&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; stripped &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;string.match&lt;/span&gt;(s, &lt;span class=&quot;string quoted single lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;#39;&lt;/span&gt;^&amp;quot;(.+)&amp;quot;$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; stripped &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; stripped
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; s
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yes, I’m using regex to parse &lt;code&gt;yaml&lt;/code&gt;/&lt;code&gt;toml&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;I could try to find a lua parser, but eeeh…&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/extend_blog/regex_this_is_fine.jpg&quot;&gt;
&lt;/figure&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I’ll probably move the content extraction to Rust so I can reuse the frontmatter parser one day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I started the rewrite less than a day after publishing this post.
See the source for the &lt;a href=&quot;https://codeberg.org/treeman/jonashietala/src/branch/master/src/json_api.rs&quot;&gt;json API&lt;/a&gt; on the backend and the &lt;a href=&quot;https://github.com/treeman/dotfiles/blob/master/.config/nvim/lua/blog/content.lua&quot;&gt;&lt;code&gt;list_posts&lt;/code&gt; command&lt;/a&gt; in Neovim.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Stupid decisions aside, with all this we have a working &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; picker!
I may have skipped some details, so &lt;a href=&quot;https://github.com/treeman/dotfiles/blob/master/.config/nvim/lua/blog/telescope.lua&quot;&gt;take a look at the source code&lt;/a&gt; if you’re interested.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Customizing Neovim</title><id>http://jonashietala.se/blog/2024/05/02/customizing_neovim/index.html</id><updated>2026-04-27T10:16:45+00:00</updated><link href="https://www.jonashietala.se/blog/2024/05/02/customizing_neovim" rel="alternate"/><published>2024-05-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;Scripting is configuration. Configuration is scripting.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;TJ DeVries &lt;a href=&quot;https://www.youtube.com/watch?v=QMVIJhC9Veg&quot;&gt;A different take on editing code&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;I’ve been using Neovim since it forked from Vim almost 8 years ago, and I used Vim many years before that.
I feel quite comfortable with Neovim, and I’ve gone down the &lt;a href=&quot;/blog/2023/10/01/rewriting_my_neovim_config_in_lua&quot;&gt;configuration rabbit hole&lt;/a&gt; too many times I’d like to admit, but I never dove deeper by writing something truly custom like a plugin.&lt;/p&gt;
&lt;p&gt;That changed when I got inspired by the excellent &lt;a href=&quot;https://www.youtube.com/watch?v=HXABdG3xJW4&quot;&gt;Developing a Neovim Docker Plugin from Scratch&lt;/a&gt; where the creator goes through how to extend &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt; in a very pedagogical manner.&lt;/p&gt;
&lt;p&gt;I was only planning to make a simple telescope picker…
Yet I fell into rabbit hole &lt;em&gt;again&lt;/em&gt; and ended up implementing some cool features such as:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Browse posts using &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope.nvim&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Autocomplete post urls, link definitions, and more using &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;nvim-cmp&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Goto definition.
&lt;/li&gt;
&lt;li&gt;
Diagnostics.
&lt;/li&gt;
&lt;li&gt;
Browser preview with auto refresh and scroll.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because of my overambitious self, I couldn’t squeeze all these topics into a single blog post, so I split the post &lt;a href=&quot;/series/extending_neovim_for_my_blog&quot;&gt;into a series&lt;/a&gt;.
This first post will go through how to get started configuring Neovim with a basic setup and some user commands, leaving the more advanced topics for later posts.&lt;/p&gt;
&lt;p&gt;See the source for the &lt;a href=&quot;https://github.com/treeman/dotfiles/tree/master/.config/nvim/lua/blog&quot;&gt;Neovim blog integration&lt;/a&gt; on GitHub and the &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;site source&lt;/a&gt; on Codeberg.&lt;/p&gt;
&lt;section id=&quot;Initial-setup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Initial-setup&quot; class=&quot;heading-ref&quot;&gt;Initial setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While I could develop this as a normal plugin, because it’s for my personalized blogging setup I decided to organize it under &lt;code&gt;nvim/lua/blog&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;lua/blog/
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── autocmd.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── cmp.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── commands.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── content.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── diagnostics.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── files.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── goto.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── init.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── path.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── server.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;└── telescope.lua
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And include the relevant code in my init script at &lt;code&gt;init.lua&lt;/code&gt; (well, really &lt;code&gt;lua/config/init.lua&lt;/code&gt; but a white lie to make it easier to grokk doesn’t hurt):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This calls &lt;code&gt;lua/blog/init.lua&lt;/code&gt; that in turn requires other initialization files:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.autocmd&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.cmp&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.commands&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above files handles the initial registration, the other files are required when they’re needed.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;autocmd.lua&lt;/code&gt; registers a 
&lt;code class=&quot;highlight lua&quot;&gt;{ &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufRead&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufNewFile&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }&lt;/code&gt; autocommand that establishes a connection to the backend, and registers buffer local keymaps:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; This way we include other blog related functionality
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.path&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; server &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.server&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; diagnostics &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.diagnostics&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; keymaps &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.keymaps&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; autocmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.api.nvim_create_autocmd
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; augroup &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.api.nvim_create_augroup
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; blog_group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; augroup(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { clear &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Only handle Djot files inside the blog directory
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; (at `~/code/jonashietala`).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; autocmd_pattern &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; path.blog_path &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;*.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; The callback function is called whenever a `.dj` file
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; is read or created.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;autocmd({ &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufRead&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BufNewFile&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  pattern &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; autocmd_pattern,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; blog_group,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(opts)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Register buffer local keymaps.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    keymaps.buf_blog(opts.buf)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Other initialization go here...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One quirk of my &lt;a href=&quot;/blog/2023/10/01/rewriting_my_neovim_config_in_lua&quot;&gt;Neovim config&lt;/a&gt; is that I’ve tried to collect all keymaps in one file, where I added some new keymaps for the blog:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; map &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.keymap.set
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Called via `init.lua`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;M.init &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;gd&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.telescope&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_draft, { desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Find blog draft&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;gp&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.telescope&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_post, { desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Find blog post&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Lots of other keymaps...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Used by the &amp;quot;BufRead&amp;quot;, &amp;quot;BufNewFile&amp;quot; autocommand shown above.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;M.buf_blog &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(buffer)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;localleader&amp;gt;t&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.telescope&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_tags, { buffer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; buffer, desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;List tags&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;localleader&amp;gt;d&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.goto&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).goto_def, { buffer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; buffer, desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Goto definition&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;buf_blog&lt;/code&gt; is called by the autocommand when editing a blog post.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Creating-and-moving-posts&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Creating-and-moving-posts&quot; class=&quot;heading-ref&quot;&gt;Creating and moving posts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the basic features I want is having user commands that simplify my life a little—like creating a new post.&lt;/p&gt;
&lt;p&gt;When I write a blog post I start by creating a markup file in &lt;code&gt;drafts/&lt;/code&gt;, that should contain a frontmatter with some metadata like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;---toml&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Customizing Neovim&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;Lua&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Neovim&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;series&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;extending_neovim_for_my_blog&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;---&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When I feel the post is done I “promote” the draft to a blog post by moving it from &lt;code&gt;drafts/&lt;/code&gt; to &lt;code&gt;posts/&lt;/code&gt;, while adding the release date to the path.&lt;/p&gt;
&lt;p&gt;I didn’t do this file manipulation manually—that would be &lt;em&gt;crazy&lt;/em&gt;—I had it implemented as an option in the blog generation tool
(the blog is a static site, generated by a &lt;a href=&quot;/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit/&quot;&gt;Rust command-line program&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I think it’s better to to have this kind of manipulation inside Neovim, which is a good starting point for our customization.&lt;/p&gt;
&lt;section id=&quot;User-commands&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#User-commands&quot; class=&quot;heading-ref&quot;&gt;User commands&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I think implementing them as user commands makes sense—I’ll forget them if I create I keybinding for them. (I know, I tried.)&lt;/p&gt;
&lt;p&gt;I setup user commands in &lt;code&gt;blog/commands.lua&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; cmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;util&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).create_cmd
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; files &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.files&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Create a new draft, promote it to a post, or revert it back to a draft.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BlogNewDraft&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, files.new_draft)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BlogPromoteDraft&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, files.promote_curr_draft)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;BlogDemotePost&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, files.demote_curr_post)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In Neovim you can use &lt;code&gt;vim.api.nvim_create_user_command&lt;/code&gt; to create a user command.
Because it takes three arguments, with the third options argument only being empty, I use the helper &lt;code&gt;create_cmd&lt;/code&gt; to make it optional:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; A module file in lua by convention use an `M` table,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; allowing us to call`require(&amp;quot;util&amp;quot;).create_cmd(...)`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; M &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;M.create_cmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(command, f, opts)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  opts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; opts &lt;span class=&quot;keyword operator lua&quot;&gt;or&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  vim.api.nvim_create_user_command(command, f, opts)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; M
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;New-draft&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#New-draft&quot; class=&quot;heading-ref&quot;&gt;New draft&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Creating a draft should do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a file at &lt;code&gt;drafts/some_title.dj&lt;/code&gt; under the blog directory.
&lt;/li&gt;
&lt;li&gt;
Open it and fill in some placeholder data.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Creating a file and opening it can be done using &lt;code&gt;vim.cmd&lt;/code&gt; to send the &lt;code&gt;:edit&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Inserting text from lua was harder to figure out, I tried to search Neovim’s help with &lt;code&gt;:Telescope help_tags&lt;/code&gt; but came up short.
In the end I found &lt;code&gt;vim.api.nvim_buf_set_lines&lt;/code&gt; via Google that can be used to insert lines.&lt;/p&gt;
&lt;p&gt;This is the solution I came up with:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;blog.path&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; nio &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nio&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; M &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;M.new_draft &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  nio.run(&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Prompt for the title of the new draft.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; nio.ui.input({ prompt &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Draft title: &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Create and open the draft for edit (without checking if it exists...)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; `path.blog_path` expands to the path to my blog and `slugify` converts
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; a title to a slug by replacing spaces with underscores and removing symbols.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; file_path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; path.blog_path &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;drafts/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; M.slugify(title) &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;:e &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; file_path)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; The text the draft will start with.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; template &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;---toml&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted single lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;#39;&lt;/span&gt;title = &amp;quot;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; title &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted single lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;#39;&lt;/span&gt;&amp;quot;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted single lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;#39;&lt;/span&gt;tags = [&amp;quot;Some tag&amp;quot;]&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;---&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Insert the text into the current buffer (0) at row 0 (to 0).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    vim.api.nvim_buf_set_lines(&lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;constant numeric lua&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, template)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Convert a title to a &amp;quot;slug&amp;quot; used in the post path and url.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; for example, converts `My title` to `my_title`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;M.slugify &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(title)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; title:lower()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Remove disallowed characters.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; title:gsub(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[^ a-zA-Z0-9_-]+&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Convert spaces and multiple `_` to a single `_`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; title:gsub(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[ _]+&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Remove dashes and underscores from the beginning and end.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; title:gsub(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;^[ _-]+&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  title &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; title:gsub(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[ _-]+$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; title
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; M
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I hope it’s clear what the above code is doing, but I want to call out the usage of &lt;a href=&quot;https://github.com/nvim-neotest/nvim-nio&quot;&gt;nvim-nio&lt;/a&gt;.
It’s a great library that makes asynchronous programming simple in Neovim.&lt;/p&gt;
&lt;p&gt;To start an async task you use &lt;code&gt;nio.run&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;nio.run(&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Code here is run async
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For this example of creating a new draft async is overkill.
Async is required for some other situations and it’s easy to add so I use it liberally, even when not strictly needed.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Moving-files&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Moving-files&quot; class=&quot;heading-ref&quot;&gt;Moving files&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In my blogging setup I store posts under &lt;code&gt;posts/&lt;/code&gt; with the release date in the path, and drafts under &lt;code&gt;drafts/&lt;/code&gt;.
So promoting and demoting is accomplished by moving the file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Promote a draft to a post by moving it from &lt;code&gt;drafts/post_title.dj&lt;/code&gt; to &lt;code&gt;posts/2024-04-14-post_title.dj&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Demote a post by moving it from &lt;code&gt;posts/2024-04-14-post_title.dj&lt;/code&gt; to &lt;code&gt;drafts/post_title.dj&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead of pasting a big chunk of code, let’s go through the most important implementation details:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I want to use the title from the metadata because I’ll often change the title and I want the slug to be updated.&lt;/p&gt;
&lt;p&gt;We can extract the title from the post by shelling out to &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt; that matches against a 
&lt;code class=&quot;highlight toml&quot;&gt;&lt;span class=&quot;property&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;My title&amp;quot;&lt;/span&gt;
&lt;/code&gt; line.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nvim-neotest/nvim-nio&quot;&gt;nvim-nio&lt;/a&gt; provides &lt;code&gt;process.run&lt;/code&gt; to run a shell command:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; proc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; nio.process.run(args)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;proc.stdout.read()
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can use &lt;code&gt;process.run&lt;/code&gt; to run &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt; to search for the title by passing this table as &lt;code&gt;args&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;{
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  cmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;rg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  args &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;-INo&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;^title = (.+)$&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    path,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because we might get multiple matches (such as in this post), we can extract it using Lua:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; output:match(&lt;span class=&quot;string quoted single lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;#39;&lt;/span&gt;title = &amp;quot;([^%&amp;quot;]+)&amp;quot;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not the prettiest solution I’ve come up with.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Another solution would be to rely on the Rust blog generation tool to provide the title;
it would be more robust since the backend properly parses the file.
I started with this route as one of my goals with customizing Neovim was to familiarize myself more with Lua.
I may move it in the future if the need arises.&lt;/p&gt;
&lt;/aside&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the destination path.&lt;/p&gt;
&lt;p&gt;For example a post path is created like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;path.blog_path
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;posts/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;os.date&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;%Y-%m-%d&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;-&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; M.slugify(title)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;.dj&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move the file.&lt;/p&gt;
&lt;p&gt;I don’t know what the idiomatic way to rename a file is, or even how to do it in Neovim using Lua.
But I do know that with &lt;code&gt;:!&lt;/code&gt; you can call an external program… Like &lt;code&gt;mv&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;So here’s one way to rename a file, that works for me on Linux:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;:!mv &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; from &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; to)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;:e &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; to)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because everything is done in an async context (inside &lt;code&gt;nio.run&lt;/code&gt;) we run into a problem: we can’t call the Neovim API.
We’ll get an error like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;...e/tree/.local/share/nvim/lazy/nvim-nio/lua/nio/tasks.lua:95: Async task failed without callback: The co
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;routine failed with this message:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim/_editor.lua:0: E5560: nvim_exec2 must not be called in a lua loop callback
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;stack traceback:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        [C]: in function &apos;nvim_exec2&apos;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        vim/_editor.lua: in function &apos;cmd&apos;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        /home/tree/.config/nvim/lua/blog/files.lua:82: in function &apos;_rename&apos;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        /home/tree/.config/nvim/lua/blog/files.lua:116: in function &lt;/home/tree/.config/nvim/lua/blog/file
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;s.lua:106&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The error to look out for is &lt;code&gt;nvim_exec2 must not be called in a lua loop callback&lt;/code&gt;, which I assume means that &lt;code&gt;nio&lt;/code&gt; uses the lower level lua loop API for its async system.&lt;/p&gt;
&lt;p&gt;What we need to do is yield to the Neovim scheduler before calling &lt;code&gt;vim.cmd&lt;/code&gt; to rename the file, which can be done with 
&lt;code class=&quot;highlight lua&quot;&gt;nio.scheduler()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;nio.scheduler()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Now we can call `vim.cmd` and `vim.fn`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;More-functionality&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#More-functionality&quot; class=&quot;heading-ref&quot;&gt;More functionality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have some more user commands for creating other types of files; &lt;a href=&quot;/series&quot;&gt;series&lt;/a&gt;, &lt;a href=&quot;/projects&quot;&gt;projects&lt;/a&gt;, and standalones (see &lt;a href=&quot;/uses&quot;&gt;/uses&lt;/a&gt;) but they work exactly the same as creating drafts.
There are a few other commands that I’ll bring up in future posts, which will go into more advanced functionality.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s create a Tree-sitter grammar</title><id>http://jonashietala.se/blog/2024/03/19/lets_create_a_tree-sitter_grammar/index.html</id><updated>2026-04-27T10:59:37+00:00</updated><link href="https://www.jonashietala.se/blog/2024/03/19/lets_create_a_tree-sitter_grammar" rel="alternate"/><published>2024-03-19T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;One of my favorite features in Neovim is the Tree-sitter integration.
It allows for fast syntax highlighting that works well even in an error state (often the case when you’re editing code), and it has additional semantics (you can differentiate between function parameters and local variables).&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter-textobjects&quot;&gt;nvim-treesitter-textobjects&lt;/a&gt; you can also jump between nodes (such as &lt;code&gt;]c&lt;/code&gt; to jump to next class) or target deletion (&lt;code&gt;cif&lt;/code&gt; to delete the function body and enter insert mode).
An amazing feature as it works across languages, no matter how they look like, as long as they have a Tree-sitter grammar (most do).&lt;/p&gt;
&lt;p&gt;But, you might wonder what does a Tree-sitter grammar look like,
and how do you create one for a language?&lt;/p&gt;
&lt;p&gt;I started thinking about this and before I knew it I was &lt;a href=&quot;https://codeberg.org/treeman/tree-sitter-djot&quot;&gt;trying to make my own parser&lt;/a&gt; for &lt;a href=&quot;https://djot.net/&quot;&gt;Djot&lt;/a&gt; (a markup language similar to Markdown).
There are some good tutorials on how to get started, but not on some more advanced things.&lt;/p&gt;
&lt;p&gt;I spent quite some time trying to figure it out—while refreshing my 10 year old knowledge of grammars—and decided to document some of my findings.&lt;/p&gt;
&lt;p&gt;The post spiraled out of control a little, and it will go through:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
How to use an external scanner
&lt;/li&gt;
&lt;li&gt;
Using Tree-sitter’s built-in conflicts resolution
&lt;/li&gt;
&lt;li&gt;
Syntax highlighting with language injection
&lt;/li&gt;
&lt;li&gt;
Use the grammar from Neovim for syntax highlighting and textobjects
&lt;/li&gt;
&lt;li&gt;
Embed the grammar into this Blog for syntax highlighting
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The source code for the complete grammar we’ll develop &lt;a href=&quot;https://codeberg.org/treeman/tree-sitter-sdjot&quot;&gt;can be found on Codeberg&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;Our-subset&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Our-subset&quot; class=&quot;heading-ref&quot;&gt;Our subset&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the purpose of this blog post, we’ll implement a small subset of &lt;a href=&quot;https://djot.net/&quot;&gt;Djot&lt;/a&gt;, where we’ll support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Paragraphs
&lt;/li&gt;
&lt;li&gt;
Divs
&lt;/li&gt;
&lt;li&gt;
Code blocks
&lt;/li&gt;
&lt;li&gt;
Emphasis
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This will allow us to parse markup like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;This is a&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;multiline &lt;span class=&quot;markup italic&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;_&lt;/span&gt;paragraph&lt;span class=&quot;punctuation delimiter&quot;&gt;_&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;This is a paragraph inside a div&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;tag attribute&quot;&gt;gleam&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Yes, the &lt;code&gt;sdjot&lt;/code&gt; highlight uses our grammar.)&lt;/p&gt;
&lt;p&gt;At first blush, this seems like it’s too simple to require anything more complex than some simple grammar rules, but later on we’ll see that even these simple rules requires a bit more effort to fully support.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Simple-beginnings&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Simple-beginnings&quot; class=&quot;heading-ref&quot;&gt;Simple beginnings&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The point of this post isn’t to go through how the Tree-sitter grammar description in &lt;code&gt;grammar.js&lt;/code&gt; works.
The &lt;a href=&quot;https://tree-sitter.github.io/tree-sitter/creating-parsers&quot;&gt;Tree-sitter docs&lt;/a&gt; goes through how to get started.
I named the project &lt;code&gt;sdjot&lt;/code&gt; and this is the &lt;code&gt;grammar.js&lt;/code&gt; we’ll start with:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;module&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;keyword operator assignment js&quot;&gt;=&lt;/span&gt; grammar&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta mapping js&quot;&gt;&lt;span class=&quot;punctuation section mapping begin js&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  name&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;sdjot&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; Skip carriage returns.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; We could skip spaces here as well, but the actual markup language
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; has significant spaces in some places, so let&amp;#39;s remove them here too.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;extras&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\r&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  rules&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta mapping js&quot;&gt;&lt;span class=&quot;punctuation section mapping begin js&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;document&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; repeat&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_block&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; All blocks should end with a newline, but we can also parse multiple newlines.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;_block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; choice&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;code_block&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; A div contains other blocks.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;div&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      prec&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;div_marker&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; repeat&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_block&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;div_marker&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;div_marker&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;:::&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; Code blocks may have a language specifier.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;code_block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;code_block_marker&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        optional&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        optional&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;code_block_marker&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;code_block_marker&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;```&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;code&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; repeat1&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;keyword operator negation regexp&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;language&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;keyword operator negation regexp&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;constant other character-class escape backslash regexp&quot;&gt;\s&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; A paragraph contains inline content and is terminated by a blankline
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; (two newlines in a row).
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;paragraph&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;repeat&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inline&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; The markup parser could separate block and inline parsing into separate steps,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; but we&amp;#39;ll do everything in one parser.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;_inline&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; repeat1&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;choice&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;emphasis&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_text&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;emphasis&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; prec&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inline&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta mapping key js&quot;&gt;&lt;span class=&quot;entity name function js&quot;&gt;_text&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;keyword operator negation regexp&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section mapping end js&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section mapping end js&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator statement js&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It recognizes paragraphs with text and emphasis, and it identifies divs and code blocks.&lt;/p&gt;
&lt;p&gt;We can create an &lt;code&gt;example-file&lt;/code&gt; with these contents:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;A paragraph &lt;span class=&quot;markup italic&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;_&lt;/span&gt;with emphasis&lt;span class=&quot;punctuation delimiter&quot;&gt;_&lt;/span&gt;&lt;/span&gt; inside a div&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And parse it with the &lt;code&gt;tree-sitter&lt;/code&gt; cli:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;tree-sitter&lt;/span&gt; parse example-file
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;(document [0, 0] - [5, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (div [0, 0] - [4, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div_marker [0, 0] - [0, 3])
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (paragraph [1, 0] - [3, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      (emphasis [1, 12] - [1, 27]))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div_marker [3, 0] - [3, 3])))
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Et voilà!&lt;/p&gt;
&lt;section id=&quot;Missing-features&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Missing-features&quot; class=&quot;heading-ref&quot;&gt;Missing features&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;But I told you it wasn’t supposed to be this easy, and there are features missing from our parser.
Most notably:&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
There can be an arbitrary number of &lt;code&gt;:&lt;/code&gt;, allowing divs to be nested.
&lt;/li&gt;
&lt;li&gt;
Closing a div should close other open blocks (divs and paragraphs in our case).
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In essence, we need to be able to parse this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;Top-level div&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;::::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;A paragraph inside a second div,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;both closed when the top-level div is closedj&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is… Complicated.&lt;/p&gt;
&lt;p&gt;Sure, we can work around the varying levels of &lt;code&gt;:&lt;/code&gt; with something hacky like enumerating the number of colons, using something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; choice&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div3&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div4&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div5&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div6&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div7&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div8&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_div3&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{3}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inside_div&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{3}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_div4&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{4}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inside_div&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{4}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_div5&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{5}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inside_div&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{5}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_div6&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{6}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inside_div&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{6}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_div7&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{7}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inside_div&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{7}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_div8&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{8}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inside_div&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;:&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;{8}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_inside_div&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; prec&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; repeat&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_block&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But it’s not &lt;em&gt;neat&lt;/em&gt;, and automatically closing contained blocks is much harder (to my brain it seems impossible, but I’m no expert).&lt;/p&gt;
&lt;p&gt;With an external scanner we can do this (and more).&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;External-scanner&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#External-scanner&quot; class=&quot;heading-ref&quot;&gt;External scanner&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Tree-sitter parser is actually a C program.
The grammar we’ve seen has been described in JavaScript, but it’s only used as a description to generate the parser in C.
If you’re a masochist, you can take a look at it in &lt;code&gt;src/parser.c&lt;/code&gt; after running &lt;code&gt;tree-sitter generate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An external scanner is just some custom C code that’s inserted into the parser, and it allows us to override the parser precedence, keep track of a context state, or whatever else we might need or want to do.&lt;/p&gt;
&lt;p&gt;To get started the &lt;a href=&quot;https://tree-sitter.github.io/tree-sitter/creating-parsers#external-scanners&quot;&gt;official docs&lt;/a&gt; was pretty good.
Basically you need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a &lt;code&gt;src/scanner.c&lt;/code&gt; and include it in &lt;code&gt;binding.gyp&lt;/code&gt; &lt;code&gt;bindings/rust/build.rs&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Setup &lt;code&gt;externals&lt;/code&gt; tokens in &lt;code&gt;grammar.js&lt;/code&gt; and a matching C enum in &lt;code&gt;scanner.c&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Define and implement five C functions.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s take a look.&lt;/p&gt;
&lt;section id=&quot;Div-markers-closes-open-paragraphs&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Div-markers-closes-open-paragraphs&quot; class=&quot;heading-ref&quot;&gt;Div markers closes open paragraphs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s start by closing a paragraph early when a &lt;code&gt;:::&lt;/code&gt; is encountered.
This is simpler because we can solve this without storing any state.&lt;/p&gt;
&lt;p&gt;When parsing &lt;code&gt;$.paragraph&lt;/code&gt; we’ll give the parser a choice between ending the paragraph on a newline or on our new &lt;code&gt;$._close_paragraph&lt;/code&gt; token:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;repeat&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inline&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; choice&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_close_paragraph&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;$._close_paragraph&lt;/code&gt; is handled by the external scanner, which is specified using the &lt;code&gt;externals&lt;/code&gt; field:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;externals&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_close_paragraph&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let’s turn our attention to &lt;code&gt;src/scanner.c&lt;/code&gt;.
The tokens in &lt;code&gt;externals&lt;/code&gt; gets assigned an incremented number, starting from 0…
Just like an enum in C!&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; We only have a single element right now, but keep in mind that the order
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; must match the `externals` array in `grammar.js`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt; CLOSE_PARAGRAPH &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;TokenType&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The five functions we need to implement are these:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; You should replace `sdjot` with whatever project name you chose.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_scan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                             &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; All the scanning goes here.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; If we need to allocate/deallocate state, we do it in these functions.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_create&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt; &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_destroy&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; If we have state, we should load and save it in these functions.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_serialize&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                                      &lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_deserialize&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                                    &lt;span class=&quot;storage type c&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because we won’t use any state, we’ll only have to update the &lt;code&gt;scan&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;What you’re supposed to do is check &lt;code&gt;valid_symbols&lt;/code&gt; for the tokens we can return at any point in time, and return &lt;code&gt;true&lt;/code&gt; if any was found:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_scan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                             &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;valid_symbols&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;CLOSE_PARAGRAPH&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;parse_close_paragraph&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To decide if we’re going to close the paragraph early, we’ll look ahead for any &lt;code&gt;:::&lt;/code&gt;, and if so we’ll close it without consuming any characters.
This might not be the most efficient solution because we’ll have to parse the &lt;code&gt;:::&lt;/code&gt; again, but it gets the job done.&lt;/p&gt;
&lt;p&gt;The matched token should be stored in 
&lt;code class=&quot;highlight c&quot;&gt;lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;parse_close_paragraph&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Mark the end before advancing so that the CLOSE_PARAGRAPH token doesn&amp;#39;t
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; consume any characters.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;mark_end&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; colons &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;consume_chars&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted single c&quot;&gt;&lt;span class=&quot;punctuation definition string begin c&quot;&gt;&amp;#39;&lt;/span&gt;:&lt;span class=&quot;punctuation definition string end c&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;colons &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; CLOSE_PARAGRAPH&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control c&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the resulting token will mark any symbol we advance over as owned by that token.
So &lt;code&gt;:::&lt;/code&gt; would be marked as &lt;code&gt;_close_paragraph&lt;/code&gt; (which will be ignored by the output since it begins with an underscore), instead of &lt;code&gt;div_marker&lt;/code&gt;.
To prevent this, we turn &lt;code&gt;_close_paragraph&lt;/code&gt; into a zero-width token by marking the end before advancing the lexer.&lt;/p&gt;
&lt;p&gt;How do we advance the lexer?
We call 
&lt;code class=&quot;highlight c&quot;&gt;lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;advance&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;consume_chars&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; count &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;lookahead &lt;span class=&quot;keyword operator comparison c&quot;&gt;==&lt;/span&gt; c&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;advance&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;count&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; count&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is almost all we can do with the lexer.
We only process one character at a time, cannot look behind, and our only tool to look ahead is to &lt;code&gt;mark_end&lt;/code&gt; at the correct place.
(We can also query the current column position.)&lt;/p&gt;
&lt;p&gt;With this we have a working external scanner and div tags now close paragraphs:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;A paragraph inside a div&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;tree-sitter&lt;/span&gt; parse example-file
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;(document [0, 0] - [4, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (div [0, 0] - [3, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div_marker [0, 0] - [0, 3])
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (paragraph [1, 0] - [2, 0])
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div_marker [2, 0] - [2, 3])))
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Nested-blocks&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Nested-blocks&quot; class=&quot;heading-ref&quot;&gt;Nested blocks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To automatically close other open blocks we need to add some context to our parser, which means we’ll need state management.&lt;/p&gt;
&lt;p&gt;The small subset we’re implementing is only concerned with closing divs—because it would be a terribly long post otherwise—but I’ll try to implement this in a general manner, to be more indicative of a real-world parser.&lt;/p&gt;
&lt;p&gt;Our strategy is this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A div can have a varying number of &lt;code&gt;:&lt;/code&gt; that must match.&lt;/p&gt;
&lt;p&gt;Therefore we’ll parse colons in an external scanner and store it on a stack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When we find a div marker, we’ll need to decide if it should start a new div, or close an existing one.&lt;/p&gt;
&lt;p&gt;We’ll look at the stack of open blocks and see if we find a match.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If we have need to close a nested div, that is if we want to close a div further down the stack, we need to close the nested div(s) first.&lt;/p&gt;
&lt;p&gt;Thus we’ll introduce a &lt;code&gt;block_close&lt;/code&gt; marker that ends a div, and leave the ending div marker as optional.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First we’ll ask the grammar to let the external scanner manage the begin and end tokens.
We’ll use a &lt;code&gt;_block_close&lt;/code&gt; marker to end the div, and leave the end marker optional.
(You could probably use a &lt;code&gt;choice()&lt;/code&gt; between the two, but this made more sense to me when I was implementing it.)&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  prec&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; A rule starting with &amp;quot;_&amp;quot; will be hidden in the output,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; and we can use &amp;quot;alias&amp;quot; to rename rules.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      alias&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div_marker_begin&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;div_marker&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape js&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      repeat&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_block&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_block_close&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      optional&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;alias&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div_marker_end&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;div_marker&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;externals&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_close_paragraph&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_block_close&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div_marker_begin&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_div_marker_end&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; This is used in the scanner internally,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; but shouldn&amp;#39;t be used by the grammar.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_ignored&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And remember to update the list of external tokens in the scanner (order matters):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  CLOSE_PARAGRAPH&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  BLOCK_CLOSE&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  DIV_MARKER_BEGIN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  DIV_MARKER_END&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta assumed-macro c&quot;&gt;  IGNORED
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;TokenType&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then to our stack of blocks.&lt;/p&gt;
&lt;p&gt;I used a &lt;code&gt;Block&lt;/code&gt; type to keep track of the type and number of colons:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; In a real implementation we&amp;#39;ll have more block types.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt; DIV &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;BlockType&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  BlockType type&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; level&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;Block&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I know that &lt;code&gt;level&lt;/code&gt; isn’t the best name, but I couldn’t find a very good general name for the number of colons, indentation level, etc.
With sum types you could model it in a clearer way, like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta enum rust&quot;&gt;&lt;span class=&quot;storage type enum rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;entity name enum rust&quot;&gt;Block&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Div &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; colons&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;u32&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Footnote &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; indent&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;u32&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; etc
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;I will, in fact, claim that the difference between a bad programmer and a good one
is whether he considers his code or his data structures more important.
Bad programmers worry about the code.
Good programmers worry about data structures and their relationships.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Linus Torvalds
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;But I digress, I’ll go with &lt;code&gt;level&lt;/code&gt; like a bad programmer.&lt;/p&gt;
&lt;p&gt;Another joy of programming C is that you’ll get to re-implement standard data structures such as a growable stack.
It’s not truly difficult, but it’s annoying and bug-prone.&lt;/p&gt;
&lt;p&gt;Luckily, during the time I’m writing this blog post, &lt;a href=&quot;https://github.com/tree-sitter/tree-sitter/releases/tag/v0.22.1&quot;&gt;tree-sitter 0.22.1&lt;/a&gt; was released with an array implementation.
So now I don’t have to show you my shoddy stack implementation, and we can use their array for our stack instead.&lt;/p&gt;
&lt;p&gt;We’ll shove our &lt;code&gt;Array&lt;/code&gt; of &lt;code&gt;Block*&lt;/code&gt; into a &lt;code&gt;Scanner&lt;/code&gt; struct, because we’ll need to track more data later:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor include c&quot;&gt;&lt;span class=&quot;keyword control import include c&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;string quoted double include c&quot;&gt;&lt;span class=&quot;punctuation definition string begin c&quot;&gt;&amp;quot;&lt;/span&gt;tree_sitter/array.h&lt;span class=&quot;punctuation definition string end c&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Block &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt; open_blocks&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;Scanner&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you manage state in tree-sitter, you need to do some data management in the &lt;code&gt;tree_sitter_&lt;/code&gt; functions we defined earlier.&lt;/p&gt;
&lt;p&gt;Allocations are managed in the &lt;code&gt;_create&lt;/code&gt; and &lt;code&gt;_destroy&lt;/code&gt; functions.
Also new for 0.22.1 is the recommendation to use &lt;code&gt;ts_&lt;/code&gt; functions for allocations, to allow consumers to override the default allocator:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor include c&quot;&gt;&lt;span class=&quot;keyword control import include c&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;string quoted double include c&quot;&gt;&lt;span class=&quot;punctuation definition string begin c&quot;&gt;&amp;quot;&lt;/span&gt;tree_sitter/alloc.h&lt;span class=&quot;punctuation definition string end c&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_create&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;s &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ts_malloc&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;keyword operator word c&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; This is how you create an empty array
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ts_malloc&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;keyword operator word c&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Block &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_init&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_destroy&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;s &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;payload&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; I haven&amp;#39;t shown the allocation of the blocks yet,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; but keep in mind that `array_delete` does not deallocate any memory
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; you store in the array itself.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control c&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; i &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;lt;&lt;/span&gt; s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;size&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;i&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; I use `array_get` even though you can index the contents directly.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ts_free&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_get&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; The array is a growable one, `array_delete` ensures that the
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; memory is deleted.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_delete&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ts_free&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I allocate the blocks in a &lt;code&gt;push_block&lt;/code&gt; helper:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;push_block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; BlockType &lt;span class=&quot;variable parameter c&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Block &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;b &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ts_malloc&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;keyword operator word c&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;Block&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  b&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;type &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; type&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  b&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;level &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; level&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Grows the stack automatically.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_push&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You also need to define the serialize functions.
These store and retrieve the managed state, to allow tree-sitter to backtrack.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_serialize&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                                      &lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;s &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;payload&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;storage type c&quot;&gt;unsigned&lt;/span&gt; size &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; i &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;lt;&lt;/span&gt; s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;size&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;i&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Block &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;b &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_get&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;b&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;type&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;b&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;level&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; size&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_deserialize&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                                    &lt;span class=&quot;storage type c&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;s &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;payload&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_init&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; size &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;lt;&lt;/span&gt; length&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    BlockType type &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;BlockType&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; level &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;push_block&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; level&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s the (initial) state management taken care of!&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;C is scary.
Try &lt;a href=&quot;https://valgrind.org/&quot;&gt;valgrind&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Div-markers&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Div-markers&quot; class=&quot;heading-ref&quot;&gt;Div markers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Of course, we haven’t used our state yet.
Let’s change that.&lt;/p&gt;
&lt;p&gt;First, let’s add the &lt;code&gt;parse_div&lt;/code&gt; entry point to our scan function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_scan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                             &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;s &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;payload&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Paragraph needs to be closed before we try to close divs.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;valid_symbols&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;CLOSE_PARAGRAPH&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;parse_close_paragraph&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Check `valid_symbols` inside `parse_div` because of multiple valid symbols.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;parse_div&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; valid_symbols&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because advancing the lexer is primitive, and we cannot “go back a char”, it’s important to only advance it if we really need to.
Therefore we always need to check &lt;code&gt;valid_symbols&lt;/code&gt; before we continue:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;parse_div&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;!&lt;/span&gt;valid_symbols&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;DIV_MARKER_BEGIN&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;!&lt;/span&gt;valid_symbols&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;DIV_MARKER_END&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we’ll need to consume all colons we’re at, and only continue if we see at least three:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;consume_chars&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; count &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;lookahead &lt;span class=&quot;keyword operator comparison c&quot;&gt;==&lt;/span&gt; c&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;advance&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;count&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; count&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;parse_div&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; colons &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;consume_chars&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted single c&quot;&gt;&lt;span class=&quot;punctuation definition string begin c&quot;&gt;&amp;#39;&lt;/span&gt;:&lt;span class=&quot;punctuation definition string end c&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;colons &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Opening a new div is simple; we push the block and register the number of colons:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;push_block&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; DIV&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; colons&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; DIV_MARKER_BEGIN&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But to the decide if we should open or close a div, we need a way to search through the stack.
This function does that, while also returning how many blocks deep into the stack we found the div (which we’ll use shortly):&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; How many blocks from the top of the stack can we find a matching block?
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; If it&amp;#39;s directly on the top, returns 1.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; If it cannot be found, returns 0.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;number_of_blocks_from_top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; BlockType &lt;span class=&quot;variable parameter c&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                        &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;size &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt;i&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Block &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;b &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_get&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;type &lt;span class=&quot;keyword operator comparison c&quot;&gt;==&lt;/span&gt; type &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;level &lt;span class=&quot;keyword operator comparison c&quot;&gt;==&lt;/span&gt; level&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;size &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt; i&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;parse_div&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; from_top &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;number_of_blocks_from_top&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; DIV&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; colons&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; We could check if either DIV_MARKER_BEGIN or DIV_MARKER_END are valid here,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; but as the grammar is set up they&amp;#39;re both always valid at the same time.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;from_top &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Close the current div, and all blocks above.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control c&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; No matching div to close, let&amp;#39;s open one.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;mark_end&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;push_block&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; DIV&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; colons&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; DIV_MARKER_BEGIN&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But we have a problem: when we want to close the div, we want to be able to output multiple tokens.&lt;/p&gt;
&lt;p&gt;For example, with this type of input:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::::::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;text&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll have a stack of 3 divs when we see the closing &lt;code&gt;:::&lt;/code&gt; marker:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;7 (top)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;5
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;3 (the one we want to close)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the code above, &lt;code&gt;from_top&lt;/code&gt; will be &lt;code&gt;3&lt;/code&gt; and we need to output 4 tokens: 3 &lt;code&gt;BLOCK_CLOSE&lt;/code&gt; (one for each div) and 1 &lt;code&gt;DIV_MARKER_END&lt;/code&gt; (for the last &lt;code&gt;:::&lt;/code&gt;).
But the scanner can only output a single token at a time.&lt;/p&gt;
&lt;p&gt;The way I solved this is by introducing more state to the Scanner.
Specifically, I introduced a &lt;code&gt;blocks_to_close&lt;/code&gt; variable that we’ll use to output &lt;code&gt;BLOCK_CLOSE&lt;/code&gt;, and some variables to output (and consume) the &lt;code&gt;DIV_MARKER_END&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Block &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt; open_blocks&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; How many BLOCK_CLOSE we should output right now?
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; blocks_to_close&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Delayed output of a token.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  TokenType delayed_token&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Allows us to consume the width of a delayed token.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; delayed_token_width&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;Scanner&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to remember to update the create and serialize functions too.&lt;/p&gt;
&lt;p&gt;Serialize:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token_width&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Deserialize:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;TokenType&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token_width &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;buffer&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll use &lt;code&gt;IGNORED&lt;/code&gt; as the unused token, so we’ll need to reset it when we create the scanner:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; IGNORED&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now when we scan we should first check &lt;code&gt;blocks_to_close&lt;/code&gt; and then &lt;code&gt;delayed_token&lt;/code&gt;, before we scan other things:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;tree_sitter_sdjot_external_scanner_scan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                             &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;s &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;payload&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;valid_symbols&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;BLOCK_CLOSE&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;handle_blocks_to_close&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;output_delayed_token&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; valid_symbols&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Scan the other stuff
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we see &lt;code&gt;blocks_to_close &amp;gt; 0&lt;/code&gt;, we should output a &lt;code&gt;BLOCK_CLOSE&lt;/code&gt; and remove the top block (with some sanity checks for good measure):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;remove_block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;size &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ts_free&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;array_pop&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;handle_blocks_to_close&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;open_blocks&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;size &lt;span class=&quot;keyword operator comparison c&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; If we reach eof with open blocks, we should close them all.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;eof&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;||&lt;/span&gt; s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; BLOCK_CLOSE&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;remove_block&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this we can output multiple &lt;code&gt;BLOCK_CLOSE&lt;/code&gt;, and now to handle delayed tokens:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;output_delayed_token&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                          &lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;valid_symbols&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token &lt;span class=&quot;keyword operator comparison c&quot;&gt;==&lt;/span&gt; IGNORED &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;!&lt;/span&gt;valid_symbols&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; IGNORED&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; With `delayed_token_width` we can consume the ending `:::`, for example.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control c&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token_width&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;advance&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;mark_end&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another way to design this is to have a stack of delayed tokens and then just pop that.
It’s certainly more powerful, I just happened to choose this way when I was playing around with it because it’s more explicit and it felt a little easier to follow what was happening.&lt;/p&gt;
&lt;p&gt;Either way, we can now implement the div end handling. In &lt;code&gt;parse_div&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; from_top &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;number_of_blocks_from_top&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; DIV&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; colons&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control c&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;from_top &lt;span class=&quot;keyword operator comparison c&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Found a div we should close.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;close_blocks_with_final_token&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; lexer&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; from_top&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; DIV_MARKER_END&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; colons&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword control c&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;mark_end&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;push_block&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; DIV&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; colons&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; DIV_MARKER_BEGIN&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control c&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language c&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;close_blocks_with_final_token&lt;/code&gt; is a general helper that sets up the number of blocks to close and the final token:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;c&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight c&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage type c&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;entity name function c&quot;&gt;close_blocks_with_final_token&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;Scanner &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TSLexer &lt;span class=&quot;keyword operator c&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;variable parameter c&quot;&gt;lexer&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                          &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TokenType &lt;span class=&quot;variable parameter c&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                                          &lt;span class=&quot;support type stdint c&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;variable parameter c&quot;&gt;final_token_width&lt;/span&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;remove_block&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;blocks_to_close &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;+&lt;/span&gt; count &lt;span class=&quot;keyword operator arithmetic c&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  lexer&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;result_symbol &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; BLOCK_CLOSE&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; final&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  s&lt;span class=&quot;punctuation accessor c&quot;&gt;-&amp;gt;&lt;/span&gt;delayed_token_width &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; final_token_width&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function c&quot;&gt;&lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can finally try to close divs:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::::::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;Divception&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;tree-sitter&lt;/span&gt; parse example-file
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;(document [0, 0] - [6, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (div [0, 0] - [6, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div_marker [0, 0] - [0, 5])
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div [1, 0] - [4, 3]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      (div_marker [1, 0] - [1, 3])
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      (div [2, 0] - [4, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        (div_marker [2, 0] - [2, 7])
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        (paragraph [3, 0] - [4, 0]))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      (div_marker [4, 0] - [4, 3]))))
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can see that it parses without error, the last marker closes the &lt;em&gt;second&lt;/em&gt; div correctly, and the last marker captures the final &lt;code&gt;:::&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While I’m jumping to a working implementation directly in this post, when I first did this that was of course not the case.
I found the &lt;code&gt;-d&lt;/code&gt; argument useful to see what characters are consumed and what token is output in each step.&lt;/p&gt;
&lt;p&gt;Here’s a part of the output (when scanning the final &lt;code&gt;:::&lt;/code&gt;), with some comments to point out some interesting things:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;tree-sitter&lt;/span&gt; parse example-file -d
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;process version:0, version_count:1, state:34, row:4, col:0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lex_external state:4, row:4, column:0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;                         // Scan `:::`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lexed_lookahead sym:_close_paragraph, size:0    // Output _close_paragraph
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;reduce sym:paragraph_repeat1, child_count:2
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;shift state:17
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;process version:0, version_count:1, state:17, row:4, col:0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lex_external state:3, row:4, column:0           // Still on first `:`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;                         // Scan `:::` again
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lexed_lookahead sym:_block_close, size:0        // Close div with _block_close
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;reduce sym:paragraph, child_count:2
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;shift state:12
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;process version:0, version_count:1, state:12, row:4, col:0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lex_external state:5, row:4, column:0           // Still on first `:`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lexed_lookahead sym:_block_close, size:0        // Close second div with _block_close
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;reduce sym:div, child_count:4
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;shift state:12
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;process version:0, version_count:1, state:12, row:4, col:0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lex_external state:5, row:4, column:0           // Still on first `:`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;                         // Consume `:::`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  consume character:&amp;#39;:&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;lexed_lookahead sym:div_marker, size:3          // div_marker is size 3, marks `:::`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;shift state:23
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While the output seems confusing, when you know what to look for it’s very useful.
I’ve found that a deliberate process, where I look at a single character at a time, helps me get through the problems I’ve encountered so far.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Handling-conflicts&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Handling-conflicts&quot; class=&quot;heading-ref&quot;&gt;Handling conflicts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our grammar works pretty well, but there are issues you might want to fix.
One issue, that took much longer to figure out than I care to admit, is adding a fallback to text when a markup rule doesn’t match.&lt;/p&gt;
&lt;p&gt;A simple example for our grammar is a single underscore in a paragraph:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;a_b&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’d assume this would produce a paragraph with text, but instead we get an error:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;tree-sitter&lt;/span&gt; parse example-file
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;(document [0, 0] - [2, 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (ERROR [0, 0] - [0, 3]))
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is weird, because one of the main selling points of Tree-sitter is the GLR algorithm, which should explore the different interpretations to find something that succeeds.
But for some reason, it doesn’t trigger for us.&lt;/p&gt;
&lt;p&gt;Let’s take a look.
These are the relevant lines from the grammar:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_inline&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; repeat&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;choice&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;emphasis&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_text&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;emphasis&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; prec&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inline&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_text&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;keyword operator negation regexp&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we try to match a &lt;code&gt;_&lt;/code&gt; then the grammar can match either &lt;code&gt;emphasis&lt;/code&gt; or &lt;code&gt;_text&lt;/code&gt; because &lt;code&gt;_&lt;/code&gt; matches both 
&lt;code class=&quot;highlight javascript&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; and 
&lt;code class=&quot;highlight javascript&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;keyword operator negation regexp&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;/code&gt;.
The issue seems to be that Tree-sitter doesn’t recognize this as a conflict.&lt;/p&gt;
&lt;p&gt;If we instead add a fallback with a &lt;code&gt;_&lt;/code&gt; string then Tree-sitter will treat it as a conflict:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_inline&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; repeat&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;choice&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;emphasis&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_text&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_fallback&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;emphasis&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; prec&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;seq&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_inline&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; prec.dynamic() is used during conflict resolution to choose which
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash js&quot;&gt;&lt;span class=&quot;punctuation definition comment js&quot;&gt;//&lt;/span&gt; branch to choose if multiple succeed.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;entity name label js&quot;&gt;_fallback&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; prec&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;dynamic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;keyword operator arithmetic js&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;meta number integer decimal js&quot;&gt;&lt;span class=&quot;constant numeric value js&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;_text&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;_&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string regexp js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;keyword operator negation regexp&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end js&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And when we call &lt;code&gt;tree-sitter generate&lt;/code&gt; we’re made aware of the conflict:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;tree-sitter&lt;/span&gt; generate
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Unresolved conflict for symbol sequence:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &amp;#39;_&amp;#39;  •  &amp;#39;_&amp;#39;  …
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Possible interpretations:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  1:  (_fallback  &amp;#39;_&amp;#39;)  •  &amp;#39;_&amp;#39;  …
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  2:  (emphasis  &amp;#39;_&amp;#39;  •  _inline  &amp;#39;_&amp;#39;)  (precedence: 0, associativity: Left)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Possible resolutions:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  1:  Specify a higher precedence in `emphasis` than in the other rules.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  2:  Specify a higher precedence in `_fallback` than in the other rules.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  3:  Specify a left or right associativity in `_fallback`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  4:  Add a conflict for these rules: `emphasis`, `_fallback`
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What we want to do is mark them as a conflict that’s supposed to exist in the grammar using the &lt;code&gt;conflicts&lt;/code&gt; field:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;javascript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight javascript&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name label js&quot;&gt;conflicts&lt;/span&gt;&lt;span class=&quot;punctuation separator js&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;$&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; =&lt;span class=&quot;keyword operator comparison js&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta sequence js&quot;&gt;&lt;span class=&quot;punctuation section sequence begin js&quot;&gt;[&lt;/span&gt;$&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;emphasis&lt;/span&gt;&lt;span class=&quot;punctuation separator comma js&quot;&gt;,&lt;/span&gt; $&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta property object js&quot;&gt;_fallback&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end js&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator comma js&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we can parse paragraphs containing only a single &lt;code&gt;_&lt;/code&gt; without errors.&lt;/p&gt;
&lt;p&gt;So it seems like Tree-Sitter doesn’t recognize a conflict between a string and a regex.
Another gotcha is that it doesn’t seem like you can trigger the GLR algorithm with a token returned by an external scanner, because the external scanner overrules Tree-sitter’s lexing behavior.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Some-tests&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Some-tests&quot; class=&quot;heading-ref&quot;&gt;Some tests&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using &lt;code&gt;tree-sitter parse example-file&lt;/code&gt; (with or without the &lt;code&gt;-d&lt;/code&gt; or &lt;code&gt;-D&lt;/code&gt; flags, try them if you haven’t) is fine for experimental tests, but we really should add the different test cases as proper unit tests.
Tree-sitter has a built-in test harness for this purpose.&lt;/p&gt;
&lt;p&gt;Let’s add the very first test case to &lt;code&gt;test/corpus/syntax.txt&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;===============================================================================
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Parsing goal
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===============================================================================
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;This is a
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;multiline _paragraph_
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:::
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;This is a paragraph inside a div
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:::
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;```gleam
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;let x = 2;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;```
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;-------------------------------------------------------------------------------
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;(document
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (paragraph (emphasis))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (div
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div_marker)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (paragraph)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (div_marker))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (code_block
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (code_block_marker)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (language)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (code)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    (code_block_marker)))
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And run it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ tree-sitter test
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  syntax:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ✓ Parsing goal
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yay!&lt;/p&gt;
&lt;p&gt;We should add (a lot) more tests here, but I won’t bother writing them out in this already too long blog post.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Using-tree-sitter-for-something-useful&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Using-tree-sitter-for-something-useful&quot; class=&quot;heading-ref&quot;&gt;Using tree-sitter for something useful&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like a theoretical excursion as much as the next nerd, but I started looking at Tree-sitter because I wanted to &lt;em&gt;do&lt;/em&gt; something with the Grammar, not just play around with it all day.
Let’s end the post by seeing some things we can use it for.&lt;/p&gt;
&lt;section id=&quot;Syntax-highlighting&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Syntax-highlighting&quot; class=&quot;heading-ref&quot;&gt;Syntax highlighting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Syntax highlighting is made using queries from the &lt;code&gt;highlights.scm&lt;/code&gt; file.
It’s common to have it placed in the &lt;code&gt;src&lt;/code&gt; directory in the same repository as the grammar, but it’s not required.&lt;/p&gt;
&lt;p&gt;Here’s an example &lt;code&gt;src/highlights.scm&lt;/code&gt; file that highlights the different elements of our markup:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;query&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight query&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;div_marker&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;punctuation.delimiter&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;code_block_marker&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;punctuation.delimiter&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;emphasis&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;_&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;punctuation.delimiter&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;markup.italic&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;tag.attribute&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;code_block&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;markup.raw&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;markup&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What colors to choose is a bit arbitrary, these works well enough I suppose.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://tree-sitter.github.io/tree-sitter/syntax-highlighting&quot;&gt;documentation&lt;/a&gt; for more details on how the queries and highlighting works.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Language-injection&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Language-injection&quot; class=&quot;heading-ref&quot;&gt;Language injection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One big question I had when starting writing my grammar was how to mix multiple parsers in the same document, to for example highlight code blocks using the specified language:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;tag attribute&quot;&gt;gleam&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Turns out, this is quite straightforward.&lt;/p&gt;
&lt;p&gt;With the initial grammar, the code block parses into:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;(code_block
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (code_block_marker)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (language)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (code)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  (code_block_marker)))
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which we’ll use in &lt;code&gt;src/injections.scm&lt;/code&gt; to specify that we want to parse &lt;code&gt;(code)&lt;/code&gt; using the grammar specified in &lt;code&gt;(language)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;query&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight query&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;code_block&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;injection.language&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;injection.content&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we’ll embed the grammar into a program with highlighting support, it will delegate the text inside the code block to the injected language.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Using-our-grammar-with-Neovim&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Using-our-grammar-with-Neovim&quot; class=&quot;heading-ref&quot;&gt;Using our grammar with Neovim&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/sdjot_neovim.png&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I typically install Tree-sitter grammars in Neovim using &lt;code&gt;:TSInstall&lt;/code&gt; provided by &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;nvim-treesitter&lt;/a&gt;.
But you can &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter#adding-parsers&quot;&gt;install local Tree-sitter grammars&lt;/a&gt; as well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; parser_config &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;nvim-treesitter.parsers&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).get_parser_configs()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;parser_config.sdjot &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    install_info &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Change this url to your grammar
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        url &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;~/code/tree-sitter-sdjot&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; If you use an external scanner it needs to be included here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        files &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;src/parser.c&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;src/scanner.c&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        generate_reqires_npm &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        requires_generate_from_grammar &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; The filetype you want it registered as
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    filetype &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;sdjot&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just make sure you have a &lt;code&gt;&quot;tree-sitter&quot;&lt;/code&gt; section in the grammar’s &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;json&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight json&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;tree-sitter&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;scope&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;source.sdjot&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;file-types&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;sdj&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;injection-regex&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;sdjot&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;highlights&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;queries/highlights.scm&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this you can do &lt;code&gt;:TSInstall sjdot&lt;/code&gt; and &lt;code&gt;:TSUpdate sdjot&lt;/code&gt; when you make changes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:TSInstall&lt;/code&gt; doesn’t install queries automatically though.
What I did was symlink the queries directory into Neovims config directory:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;ln&lt;/span&gt; -s ~/code/tree-sitter-sdjot/queries ~/.config/nvim/queries/sdjot
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;:TSPlaygroundToggle&lt;/code&gt; is very useful for debugging the grammar, and &lt;code&gt;:Inspect&lt;/code&gt; shows you the highlight groups under your cursor.
It might be good to check out &lt;code&gt;:help treesitter-highlight-groups&lt;/code&gt; if you want to play with your theme, as the theme needs to support the highlight groups we use for coloring to appear.&lt;/p&gt;
&lt;p&gt;You also need to have the Tree-sitter grammar for the injected language installed, if you want to highlight the contents of code blocks.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Jumping-and-selecting-with-textobjects&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Jumping-and-selecting-with-textobjects&quot; class=&quot;heading-ref&quot;&gt;Jumping and selecting with textobjects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I mentioned &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter-textobjects&quot;&gt;nvim-treesitter-textobjects&lt;/a&gt; as a good example of why Tree-sitter is about more than syntax highlighting.&lt;/p&gt;
&lt;p&gt;To make use of our grammar we can add some capture groups to &lt;code&gt;src/textobjects.scm&lt;/code&gt;.
For example we can register our code blocks as “functions”:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;query&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight query&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;code_block&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;function.inner&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation special&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;function.outer&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The objects are arbitrary, but &lt;code&gt;@function&lt;/code&gt; is one of the standard objects so I guess it might make sense.&lt;/p&gt;
&lt;p&gt;With the symlink ready, you need to register keymaps with &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter-textobjects&quot;&gt;nvim-treesitter-textobjects&lt;/a&gt; and you’re good to go.
I have it setup so I can jump between &lt;code&gt;@function.outer&lt;/code&gt; with &lt;code&gt;[f&lt;/code&gt; and &lt;code&gt;]f&lt;/code&gt;, and selections with &lt;code&gt;af&lt;/code&gt; and &lt;code&gt;if&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This means that with the above textobject definition I can for example jump to the next code block with &lt;code&gt;]f&lt;/code&gt; and then remove all the code inside with &lt;code&gt;cif&lt;/code&gt; to end up in insert mode, ready to replace it with some new code.&lt;/p&gt;
&lt;p&gt;Although this example is a bit arbitrary, this general functionality is &lt;strong&gt;&lt;em&gt;extremely&lt;/em&gt;&lt;/strong&gt; useful for programming languages.
For a markup language like &lt;a href=&quot;https://djot.net/&quot;&gt;Djot&lt;/a&gt;, jumping between headings might be a more relevant use-case.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Embedding-the-grammar-with-Rust&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Embedding-the-grammar-with-Rust&quot; class=&quot;heading-ref&quot;&gt;Embedding the grammar with Rust&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the selling points of Tree-sitter is that you should be able to embed it in any application.
Such as this blog!&lt;/p&gt;
&lt;p&gt;I’ve been wanting to add Tree-sitter powered highlighting to my blog for a while, and now I have an excuse to do just that.&lt;/p&gt;
&lt;p&gt;This blog is a static site generator written in Rust, and &lt;a href=&quot;https://docs.rs/tree-sitter-highlight/latest/tree_sitter_highlight/&quot;&gt;tree-sitter-highlight&lt;/a&gt; looks like a suitable library to try.
Let’s add it to our &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;tree-sitter-highlight&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;^0.20.0&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;tree-sitter-sdjot&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;https://codeberg.org/treeman/tree-sitter-sdjot.git&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I use a slightly older version because some other grammars I want depend on the older version, and it’s a big pain but they all need to use a matching version.
Bleh.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.rs/tree-sitter-highlight/latest/tree_sitter_highlight/&quot;&gt;According to the docs&lt;/a&gt; we first need to setup a &lt;code&gt;HighlightConfiguration&lt;/code&gt;.
I used &lt;code&gt;lazy_static!&lt;/code&gt; to create a global map with configurations to be used by any parallel rendering on the blog.
It’s not the most beautiful code I’ve written, but it gets the job done:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; All highlights needs to be listed explicitly.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;constant other rust&quot;&gt;HIGHLIGHT_NAMES&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; I have +100 entries here, this is for sdjot.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;   &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;markup&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;markup.italic&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;markup.raw&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;punctuation.delimiter&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;tag.attribute&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support macro rust&quot;&gt;lazy_static!&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;constant other rust&quot;&gt;CONFIGS&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;HashMap&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;String, HighlightConfiguration&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;init_configurations&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;init_configurations&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;HashMap&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;String, HighlightConfiguration&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; I have more languages here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;sdjot&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta path rust&quot;&gt;HighlightConfiguration&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta path rust&quot;&gt;tree_sitter_sdjot&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;language&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta path rust&quot;&gt;tree_sitter_sdjot&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant other rust&quot;&gt;HIGHLIGHTS_QUERY&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta path rust&quot;&gt;tree_sitter_sdjot&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant other rust&quot;&gt;INJECTIONS_QUERY&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            .&lt;span class=&quot;support function rust&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    .&lt;span class=&quot;support function rust&quot;&gt;into_iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    .&lt;span class=&quot;support function rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable parameter rust&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;variable parameter rust&quot;&gt;config&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        config.&lt;span class=&quot;support function rust&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;constant other rust&quot;&gt;HIGHLIGHT_NAMES&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;name.&lt;span class=&quot;support function rust&quot;&gt;to_string&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; config&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    .&lt;span class=&quot;support function rust&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice how all highlight names we’re interested in have to be explicitly specified.
This is a big pain, especially if you’re going to include many larger grammars.&lt;/p&gt;
&lt;p&gt;The names can be filtered for with &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt; with something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;rg&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;@[&lt;span class=&quot;string escape&quot;&gt;\w&lt;/span&gt;.]+&amp;quot;&lt;/span&gt; -INo --trim highlights.scm &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;uniq&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I already have syntax highlighting via &lt;a href=&quot;https://github.com/trishume/syntect&quot;&gt;syntect&lt;/a&gt;, so I wrap the highlighters in their own types:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta enum rust&quot;&gt;&lt;span class=&quot;storage type enum rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;entity name enum rust&quot;&gt;HighlighterType&lt;/span&gt;&amp;lt;&amp;#39;a&amp;gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Syntect&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;SyntectHighlighter&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Treesitter&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;TreesitterHighlighter&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;TreesitterHighlighter&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt; HighlightConfiguration,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;storage type impl rust&quot;&gt;impl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt; &lt;span class=&quot;entity name impl rust&quot;&gt;TreesitterHighlighter&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;find&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;lang_id&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Option&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;constant other rust&quot;&gt;CONFIGS&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;lang_id&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; config &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The interesting part is of course the &lt;code&gt;highlight&lt;/code&gt; method, that takes a string of code and applies syntax highlighting on it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;storage type impl rust&quot;&gt;impl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt; &lt;span class=&quot;entity name impl rust&quot;&gt;TreesitterHighlighter&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage modifier lifetime rust&quot;&gt;&amp;#39;a&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;highlight&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;, &lt;span class=&quot;variable parameter rust&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Result&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; highlighter &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Highlighter&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; highlights &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; highlighter.&lt;span class=&quot;support function rust&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.config&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; code.&lt;span class=&quot;support function rust&quot;&gt;as_bytes&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;support type rust&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; This callback handles language injection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; and should return a `HighlightConfiguration`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; res &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant other rust&quot;&gt;CONFIGS&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;lang&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;!&lt;/span&gt;res.&lt;span class=&quot;support function rust&quot;&gt;is_some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;support macro rust&quot;&gt;warn!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;Couldn&amp;#39;t find treesitter grammar for `{lang}` to inject&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            res
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; renderer &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;HtmlRenderer&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        renderer.&lt;span class=&quot;support function rust&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;highlights&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; code.&lt;span class=&quot;support function rust&quot;&gt;as_bytes&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;attr&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; This should return a `&amp;amp;&amp;#39;a [u8]` with the same lifetime as `code`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; res &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; renderer.&lt;span class=&quot;support function rust&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support type rust&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;res&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I want to point out the API in &lt;code&gt;HtmlRenderer&lt;/code&gt;, where we stumble upon a very annoying problem:
what should we return from the callback, and how should we do that?&lt;/p&gt;
&lt;p&gt;What the callback does is inject the return value into the &lt;code&gt;span&lt;/code&gt; element, like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;entity other attribute-name html&quot;&gt;CALLBACK_RESULT&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;highlight&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So we’d like to return something like 
&lt;code class=&quot;highlight rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;class=&lt;span class=&quot;constant character escape rust&quot;&gt;\&amp;quot;&lt;/span&gt;markup italic&lt;span class=&quot;constant character escape rust&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;, using &lt;code&gt;attr&lt;/code&gt; which is only a &lt;code&gt;usize&lt;/code&gt; into &lt;code&gt;HIGHLIGHT_NAMES&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;renderer.&lt;span class=&quot;support function rust&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;highlights&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; code.&lt;span class=&quot;support function rust&quot;&gt;as_bytes&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;attr&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double raw rust&quot;&gt;&lt;span class=&quot;storage type string rust&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;#&lt;/span&gt;&amp;quot;class=&amp;quot;&lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&amp;quot;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;#&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant other rust&quot;&gt;HIGHLIGHT_NAMES&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;attr.&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;as_bytes&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because we return a slice of bytes into a string that’s created inside the callback, of course the Rust compiler will be mad at us:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;error[E0515]: cannot return value referencing temporary value
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  --&gt; src/markup/syntax_highlight/treesitter_highlighter.rs:33:13
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;33 |             format!(r#&quot;class=&quot;{}&quot;&quot;#, HIGHLIGHT_NAMES[attr.0].replace(&quot;.&quot;, &quot; &quot;)).as_bytes()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   |             -------------------------------------------------------------------^^^^^^^^^^^
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   |             |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   |             returns a value referencing data owned by the current function
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   |             temporary value created here
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How to dynamically create a string from inside the callback… That outlives the callback itself?&lt;/p&gt;
&lt;p&gt;Not easily I tell you.&lt;/p&gt;
&lt;p&gt;It would be so much easier if the callback would return a &lt;code&gt;Cow&amp;lt;str&amp;gt;&lt;/code&gt; or something.
I wonder how the designers of the API expects it to be used?
This surely isn’t a very unique requirement, to wrap the attribute in a &lt;code&gt;class&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Oh well.
One way to solve this is to store the generated strings in a container that outlives the callback, and reference that (yeah it’s a &lt;code&gt;Fn&lt;/code&gt; callback, but there are hacky ways around that).
Or you could, you know, write your own &lt;code&gt;HtmlRenderer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Or you could pre-generate the classes and reference them:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support macro rust&quot;&gt;lazy_static!&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;constant other rust&quot;&gt;CLASSES&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Vec&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant other rust&quot;&gt;HIGHLIGHT_NAMES&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;support macro rust&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double raw rust&quot;&gt;&lt;span class=&quot;storage type string rust&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;#&lt;/span&gt;&amp;quot;class=&amp;quot;&lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&amp;quot;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;#&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; name.&lt;span class=&quot;support function rust&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;renderer.&lt;span class=&quot;support function rust&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;highlights&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; code.&lt;span class=&quot;support function rust&quot;&gt;as_bytes&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;attr&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other rust&quot;&gt;CLASSES&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;attr.&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;as_bytes&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should be the fastest option and is the one I currently use…
But speed isn’t a bottleneck here and I’d rather just return a &lt;code&gt;String&lt;/code&gt; with &lt;code&gt;format!&lt;/code&gt; and be done with it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;With this I’ve integrated Tree-sitter based syntax highlighting into my blog!&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;sdjot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight sdjot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;With great powers comes great responsibility&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup raw&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I could start moving the various languages over from Syntect to Tree-sitter…
But I won’t.&lt;/p&gt;
&lt;p&gt;There are some issues:&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;p&gt;You need a compatible version of &lt;code&gt;tree-sitter&lt;/code&gt; for all grammars.&lt;/p&gt;
&lt;p&gt;The more grammars you add the more painful the upgrade path becomes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Syntect gives better highlighting for some languages (like Rust and C).&lt;/p&gt;
&lt;p&gt;Neovim has their own highlighter implementation and has made tweaks to certain grammars and gets much nicer highlighting than I got out of the box.&lt;/p&gt;
&lt;p&gt;Integrating that code into my site generator is probably possible, but not a rabbit hole I want to jump into right now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The highlighter library feels a bit immature.&lt;/p&gt;
&lt;p&gt;A newer version broke the highlight groups I got from some grammars and I don’t see any support for how to add a language specific class to &lt;code&gt;span&lt;/code&gt; for injected languages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because of these issues I’ll evaluate what highlighter to use on a case-by-case basis, with Syntect as the default choice.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Within-edge-cases-lies-complexity&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Within-edge-cases-lies-complexity&quot; class=&quot;heading-ref&quot;&gt;Within edge-cases lies complexity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you’ve read the post to the end, congratulations.
You made it!&lt;/p&gt;
&lt;p&gt;I don’t claim to be an expert at grammars or Tree-sitter, and I’m sure there are plenty of things that can be improved with the way the grammar is made.
But I hope it can be helpful as a starting point if you’re curious on how to write a Tree-sitter grammar of your own.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://codeberg.org/treeman/tree-sitter-djot&quot;&gt;tree-sitter-djot repo&lt;/a&gt; for how I developed the grammar further to support the full &lt;a href=&quot;https://htmlpreview.github.io/?https://github.com/jgm/djot/blob/master/doc/syntax.html&quot;&gt;Djot specification&lt;/a&gt; (but remember, I’m not an expert).&lt;/p&gt;
&lt;p&gt;Just one word of advice before you go.
Writing a grammar for simple rules is pretty easy, but in the real world things can get messy quickly.
This is especially true if you need to juggle multiple conflicting rules in the external scanner—keeping a sane structure is challenging.&lt;/p&gt;
&lt;p&gt;(Even in our simple grammar there are bugs, but I don’t care to fix them.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The night is dark and full of terrors
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;George R.R. Martin
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Wrap-up</title><id>http://jonashietala.se/blog/2024/03/05/lets_build_a_voron_wrap-up/index.html</id><updated>2026-01-29T10:44:59+00:00</updated><link href="https://www.jonashietala.se/blog/2024/03/05/lets_build_a_voron_wrap-up" rel="alternate"/><published>2024-03-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s finally done™.
I’ve built a VORON that prints reliably and I’ve modded it enough to be able to leave it alone for a while, so I think it’s time to wrap up this build series with a little retrospective.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/finished_printing.gif&quot;&gt;
&lt;/figure&gt;
&lt;section id=&quot;Building-the-printer-was-really-fun-and-rewarding&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Building-the-printer-was-really-fun-and-rewarding&quot; class=&quot;heading-ref&quot;&gt;Building the printer was really fun and rewarding&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve always seen myself as a software person instead of a hardware person.
But I must admit, assembling the printer was a very fun and rewarding experience.&lt;/p&gt;
&lt;p&gt;Seeing how you go from bags of bits and pieces to a fully functional printer, and knowing that I—someone clueless about hardware—put everything together, is an awesome feeling.&lt;/p&gt;
&lt;p&gt;And to then mod the printer—to print out parts to modify and enhance the printer—was also very cool and one of the best parts of this project.
I think I enjoyed the building experience so much that I was seeking out more mods just to extend that sensation.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Theres-so-much-to-learn&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Theres-so-much-to-learn&quot; class=&quot;heading-ref&quot;&gt;There’s so much to learn&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even though I’ve tried to include as much details as possible in this blog series, there are still many things I left out that you need to learn if you’re new to 3D printing like I am.
For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Klipper &amp;amp; G-code configuration
&lt;/li&gt;
&lt;li&gt;
Slicer management and the thousands of settings
&lt;/li&gt;
&lt;li&gt;
Filament selection, stuck filament, wet filament, filament tuning…
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can absolutely start from zero with a VORON like I did, just realize that there’s a lot to learn, and building the printer is only the beginning of the journey.&lt;/p&gt;
&lt;p&gt;Take it slow and ask for help, and I’m sure you could do it too.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Some-modding-is-required&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Some-modding-is-required&quot; class=&quot;heading-ref&quot;&gt;Some modding is required&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Okay, you can use the printer as-is.
But in my mind some modding is required to get the most out of it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2023/12/15/lets_build_a_voron_filters/#hepa-exhaust-filter&quot;&gt;HEPA filter&lt;/a&gt; seems like a must.&lt;/p&gt;
&lt;p&gt;Sure, there are crazy people who even print ABS in their bedroom without an enclosure—but come on.
Your health is the most important thing, you should take better care of it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;a href=&quot;/blog/2024/02/27/lets_build_a_voron_more_mods/#Smart-filament-sensor&quot;&gt;smart filament sensor&lt;/a&gt; saves you so much grief.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are a lot of other great mods too, but I concede they’re not required.
If you’re building a Trident I’d at least consider these mods as well:&lt;/p&gt;
&lt;ol type=&quot;A&quot;&gt;
&lt;li&gt;
&lt;a href=&quot;/blog/2024/02/27/lets_build_a_voron_more_mods/#Removable-panels&quot;&gt;Removable top panel&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;/blog/2024/02/27/lets_build_a_voron_more_mods/#Angry-cam&quot;&gt;Some sort of camera&lt;/a&gt; (maybe not the Angry CAM).
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;/blog/2024/02/27/lets_build_a_voron_more_mods/#RockNRoll&quot;&gt;RockNRoll&lt;/a&gt; (or &lt;a href=&quot;https://mods.vorondesign.com/details/pXkXHVIUbqSWqQKJISczw&quot;&gt;inverted electronics&lt;/a&gt;, but maybe plan for that from the start).
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(Modding is also one of the most fun parts, feel free to go nuts!)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Issues-with-the-kit&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Issues-with-the-kit&quot; class=&quot;heading-ref&quot;&gt;Issues with the kit&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Overall, the printer and kit was good and I haven’t had many issues with it.
I did however have two larger issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
The &lt;a href=&quot;/blog/2024/02/28/lets_build_a_voron_noise/&quot;&gt;printer was loud&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
The &lt;a href=&quot;/blog/2024/03/01/lets_build_a_voron_major_failure/&quot;&gt;POM nuts wore out&lt;/a&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This isn’t a knock on the printer design (I think).
Maybe it was an issue with some of the parts I received in the LDO Trident kit, but I don’t know.
It could also be plain old user error.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Future-plans&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Future-plans&quot; class=&quot;heading-ref&quot;&gt;Future plans&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One might think that the printer is complete and that I won’t touch it anymore, but nooo.
Oh no, I’ve a bunch of large mods I want to do with the printer:&lt;/p&gt;
&lt;ol type=&quot;i&quot;&gt;
&lt;li&gt;
Replace the camera with a better one (maybe also a nozzle camera?).
&lt;/li&gt;
&lt;li&gt;
Remove drag chains and go umbilical.
&lt;/li&gt;
&lt;li&gt;
Complete the &lt;a href=&quot;/blog/2024/02/27/lets_build_a_voron_more_mods/#Purge-bucket-CNC-Tap&quot;&gt;purge bucket mod&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Try the &lt;a href=&quot;https://mods.vorondesign.com/details/pXkXHVIUbqSWqQKJISczw&quot;&gt;inverted electronics&lt;/a&gt; mod.
&lt;/li&gt;
&lt;li&gt;
Replace Stealthburner with the &lt;a href=&quot;https://github.com/Armchair-Heavy-Industries/Xol-Toolhead/tree/main&quot;&gt;Xol toolhead&lt;/a&gt; for better PLA cooling.
&lt;/li&gt;
&lt;li&gt;
Multimaterial with the &lt;a href=&quot;https://github.com/Enraged-Rabbit-Community/ERCF_v2&quot;&gt;Enraged Rabbit Carrot Feeder&lt;/a&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But before that I’ve identified a fatal flaw:
I only have a single printer.&lt;/p&gt;
&lt;p&gt;What should I do if I find that I’m missing a printed part when I’ve disassembled the printer to mod it?
What if I break something?
And if I’m doing a long mod the printer will be down and I can’t print things for any other project.&lt;/p&gt;
&lt;p&gt;This clearly isn’t a sustainable solution—I need a second printer.&lt;/p&gt;
&lt;p&gt;And isn’t that the best compliment one can give?
That you haven’t even finished it yet, but you’re already pining for &lt;em&gt;another one&lt;/em&gt;?&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Major failure</title><id>http://jonashietala.se/blog/2024/03/01/lets_build_a_voron_major_failure/index.html</id><updated>2026-01-29T10:44:28+00:00</updated><link href="https://www.jonashietala.se/blog/2024/03/01/lets_build_a_voron_major_failure" rel="alternate"/><published>2024-03-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/pom_bed_imbalanced.jpg&quot;&gt;
&lt;figcaption&gt;The left POM nut got ground down, making the bed fall down.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;After 600 hours, the printer met it’s first major failure.
I know I earlier &lt;a href=&quot;/blog/2024/02/02/lets_build_a_voron_smaller_fixes/#Extruder-skipping&quot;&gt;described how the extruder starter skipping&lt;/a&gt; in a big way, but that was just some filament getting stuck in the extruder.
This time a part physically broke down.&lt;/p&gt;
&lt;p&gt;What happened was that the rod on one of the Z-motors started to grind down the POM nut that holds up the bed:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/pom_chips.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;It did this so much that the threads got ground down, making the bed fall down.&lt;/p&gt;
&lt;p&gt;The POM nuts are considered expendable items, but a failure after only 600 hours “shouldn’t happen”.
But here we are.&lt;/p&gt;
&lt;section id=&quot;Potential-issues&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Potential-issues&quot; class=&quot;heading-ref&quot;&gt;Potential issues&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve tried asking around, and I’ve rounded up a couple of potential culprits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Tightening the nuts holding the POM too hard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A gap between the motor mount and the front extrusion.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/gap_holder.jpg&quot;&gt;
&lt;figcaption&gt;I found is a gap between the motor mount and the front extrusion.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This should mean that the rod would be tilting backwards at a slight angle, which might mean that the rod would catch against the nut more in that direction, increasing the attrition on the nut.&lt;/p&gt;
&lt;p&gt;The theory meshes well with the unevenly ground threads, especially since I mostly print things at a similar Z-height (as you can see in the first photo where the rod has collected a lot of flakes).&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/pom_ground_1.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/pom_ground_1.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/pom_ground_2.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/pom_ground_2.jpg&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;The threads aren’t ground down evenly.
One side is almost completely flat, while the threads are clearly visible on the other.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I used the &lt;a href=&quot;https://forum.vorondesign.com/threads/this-is-not-good.1519/#post-9936&quot;&gt;wrong grease&lt;/a&gt; for the rods (POM is self-lubricating, maybe I don’t even need grease?).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dust/dirt stuck in the nut or on the leadscrew.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An issue with the LDO kit.&lt;/p&gt;
&lt;p&gt;Someone in the VORON Discord said that this is a well-known problem with LDO Trident kits (sigh, I chose the expensive option to avoid problems like these…).&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/z_motor_type.jpg&quot;&gt;
&lt;figcaption&gt;The Z-motor I have is LDO-42STH40-1684CL300T.
I don’t know what kind of POM nut I have (it’s black and it came with the LDO kit…)
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Solutionsworkarounds&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Solutionsworkarounds&quot; class=&quot;heading-ref&quot;&gt;Solutions/workarounds&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I don’t know the actual cause of this, but I’ve done my best to address the potential issues described above.
I’ve loosened the nuts on the POM nut a bit, I’ve adjusted the motor mount, and I’ve tried to clean the leadscrews (with a toothpick of all things). In the future I’ll try to avoid the grease as well.&lt;/p&gt;
&lt;p&gt;I complained to 3DJake where I bought the kit, and they’re sending me a replacement leadscrew including a POM nut.
It’s shipping from China so the wait is very long.
In the meantime I bought a few &lt;a href=&quot;https://www.electrokit.com/leadscrew-nut-pom-tr84&quot;&gt;replacement leadscrew nuts&lt;/a&gt; (TR8*4, not the TR8*2).&lt;/p&gt;
&lt;p&gt;Replacing the nuts weren’t that hard, but I hope it’ll take more than 600 hours until the next major issue.&lt;/p&gt;
&lt;p&gt;(I’ve already started seeing dust on the leadscrew… I’ll probably replace it when the replacement arrives and hope it’ll get better.)&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Noise</title><id>http://jonashietala.se/blog/2024/02/28/lets_build_a_voron_noise/index.html</id><updated>2026-01-29T10:44:42+00:00</updated><link href="https://www.jonashietala.se/blog/2024/02/28/lets_build_a_voron_noise" rel="alternate"/><published>2024-02-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The build is going well and the printer is printing tons of random stuff and I’m generally in awe of how cool the printer is.&lt;/p&gt;
&lt;p&gt;But there’s one thing that sucks: it’s &lt;strong&gt;&lt;strong&gt;damn loud&lt;/strong&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I knew that it wouldn’t be silent, but I wasn’t prepared for this kind of noise.&lt;/p&gt;
&lt;section id=&quot;Silent-controller-fans&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Silent-controller-fans&quot; class=&quot;heading-ref&quot;&gt;Silent controller fans&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The very first mod I made (even before my first print) was to replace the LOUD skirt fans with silent &lt;a href=&quot;https://noctua.at/en/nf-a6x25-flx&quot;&gt;Noctua FN-A6x25&lt;/a&gt;.
When I say the fans were loud, I mean that they were &lt;strong&gt;&lt;strong&gt;incredibly damn loud&lt;/strong&gt;&lt;/strong&gt;.
I don’t see how anyone could be near the printer with fans this loud for a prolonged period of time.&lt;/p&gt;
&lt;p&gt;Maybe I’m just sensitive, but I digress.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nicksherlock.com/2022/01/driving-a-4-pin-computer-pwm-fan-on-the-btt-octopus-using-klipper/&quot;&gt;You can run PWM fans&lt;/a&gt;, but I didn’t see the point so I went with the simple 3-pin variant.
The fans will fit as they are and I only made some small tweaks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Used the 12V selection jumper for the fan output on the Octopus.
&lt;/li&gt;
&lt;li&gt;
Converted the 3-pin cable to a 2-pin JST connector, and used the existing fan PCB to split the Octopus output.
(You can ignore &lt;a href=&quot;https://faqs.noctua.at/en/support/solutions/articles/101000081757&quot;&gt;the yellow RPM speed signal cable&lt;/a&gt;.)
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The connection looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/noctua_wiring.jpg&quot;&gt;
&lt;figcaption&gt;The fans are connected to the PCB splitter using low-noise adapters.
It’s important to move the jumper for the PCB FAN connector.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I altered the extension cables that came with the kit because it leaves the fans intact and I can control the speed using the included low-noise adapters (I used the ultra-low-noise adapters).
I didn’t have a compatible 3-pin splitter for the fans so I used the PCB I had on hand.&lt;/p&gt;
&lt;p&gt;I also took the opportunity to cleanup the wiring and place the fans on the other side, closer to the Raspberry Pi:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/clean_wiring.jpg&quot;&gt;
&lt;figcaption&gt;The wiring looks pretty neat. I hope I don’t have to mess with it in a long time.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Message from the future: I’ve been writing these posts out of order, and I’ve had to mess with the wiring a bit.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;You could do something smart with the fan management, but I no longer hear the fans so I just leave them on all the time.
This is how I set that up in &lt;code&gt;printer.cfg&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[fan_generic controller_fan]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;## Controller fan - FAN2
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pin: PD12
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;kick_start_time: 0.5
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;max_power: 1.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;# Set the controller fan to be on from startup.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;# Speed is controlled by noctua low-noise adapter.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[delayed_gcode controller_fan_boot]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;initial_duration: 1.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    SET_FAN_SPEED FAN=controller_fan SPEED=1.0
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Nevermore-fans&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Nevermore-fans&quot; class=&quot;heading-ref&quot;&gt;Nevermore fans&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another annoyingly loud part was the fans on the Nevermore filter.
I could try to reduce the fan speeds, but that would also reduce the effectiveness of the filtering which I’m reluctant to do.&lt;/p&gt;
&lt;p&gt;Then I found an issue discussing that &lt;a href=&quot;https://github.com/nevermore3d/Nevermore_Micro/issues/29&quot;&gt;the plenum lid makes the fans loud and weak&lt;/a&gt; because it restricts the airflow.
I can only confirm that it made a noticeable difference.
It’s by no means quiet like the Noctua fans, but now it’s similar in noise level to the hotend and partcooling fans.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/nevermore_noise.jpg&quot;&gt;
&lt;figcaption&gt;It’s ugly because the prints don’t match, but it’s much quieter (and more effective).
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Loud-stepper-noise&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Loud-stepper-noise&quot; class=&quot;heading-ref&quot;&gt;Loud stepper noise&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another really annoying noise was the steppers.&lt;/p&gt;
&lt;p&gt;The first problem was them being noisy while idle.
This was solved by adding stealthchop:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;stealthchop_treshold: 999999
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But it was still really loud when moving, especially the xy steppers were super annoying.&lt;/p&gt;
&lt;p&gt;This seems to be a &lt;a href=&quot;https://klipper.discourse.group/t/stepper-0-9-deg-very-noise/6961/1&quot;&gt;common issue with some 0.9° steppers&lt;/a&gt; and I tried manage this with various config settings:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Lower &lt;code&gt;run_current&lt;/code&gt; from 0.8 to 0.6 for x- and y-stepper motors.&lt;/p&gt;
&lt;p&gt;This drastically lowered noise during movement.
It’s not silent and it’s still too loud, but it really helped.&lt;/p&gt;
&lt;p&gt;Some have suggested that raising &lt;code&gt;run_current&lt;/code&gt; might help as well, but for me that just made things worse.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Increased microsteps.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;microsteps: 128&lt;/code&gt; on xy&lt;/p&gt;
&lt;p&gt;As long as the MCU can handle it there should be no downsides(?), and it does help with lowering noise.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I tried &lt;code&gt;interpolate: true&lt;/code&gt;, but I didn’t notice any improvements.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While things mostly weren’t &lt;strong&gt;that&lt;/strong&gt; bad anymore, at certain speeds and certain angles the noise was still way too jarring for me to leave it alone.
And it wasn’t just too high speeds, sometimes decreasing the speed made it worse!&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/steppers_loud.png&quot;&gt;
&lt;figcaption&gt;77dB is loud! This was from long diagonal movement during (non-first layer) solid infill, which was one of the movements that generated the most noise.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;So I gave in and ordered two &lt;code&gt;Wantai 42BYGHM810&lt;/code&gt; steppers from Aliexpress that &lt;a href=&quot;https://klipper.discourse.group/t/stepper-0-9-deg-very-noise/6961/1&quot;&gt;according to the linked discussion&lt;/a&gt; should be much quieter. (1.8° degree steppers should generally be much better too.)&lt;/p&gt;
&lt;p&gt;After waiting quite a while, the motor I got had the correct label of &lt;code&gt;42BYGHM810&lt;/code&gt; but marked as 1.8°, despite being sold as a 0.9°.
The joy of Aliexpress sometimes…&lt;/p&gt;
&lt;p&gt;But it does seem that it is a 0.9° motor, and it was just badly labeled.&lt;/p&gt;
&lt;p&gt;Swapping the motors was very easy, just loosen the belts a bit and I could pull them out.
With some Molex Micro-Fit  3.0 4-Pin connectors (and some crimping…) I got it to run with a &lt;code&gt;run_current: 1.1&lt;/code&gt; and it’s &lt;em&gt;so much quieter&lt;/em&gt;!&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/steppers_quiet.png&quot;&gt;
&lt;figcaption&gt;The motors run at 52dB in the same conditions as the LDO motors, which is &lt;em&gt;really&lt;/em&gt; quiet.
I can’t understate how large a 20dB difference truly is.
The 63dB peak was from the filament getting pulled from the spool.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Is-it-silent&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Is-it-silent&quot; class=&quot;heading-ref&quot;&gt;Is it silent?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Of course, the printer isn’t nearly as quiet as my water cooled computer—how could it?
But these changes have made the printer &lt;em&gt;much&lt;/em&gt; quieter, which is important to me as I’m quite sensitive to noise.&lt;/p&gt;
&lt;p&gt;It’s still a bit noisy—too much if I want to sit in silence and ponder a difficult problem—
but it’s silent enough so I can have it running in the background while I’m working.
I’ll probably pause it if I’m in a call, and I won’t have it running all the time during work hours.
(The printer is in my office, right behind me.)&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s build a VORON: More mods</title><id>http://jonashietala.se/blog/2024/02/27/lets_build_a_voron_more_mods/index.html</id><updated>2026-04-27T15:26:20+00:00</updated><link href="https://www.jonashietala.se/blog/2024/02/27/lets_build_a_voron_more_mods" rel="alternate"/><published>2024-02-27T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The printer is done, but I feel one of the best part of a VORON printer is the ability to modify and personalize it.
There a &lt;strong&gt;tons&lt;/strong&gt; of mods you can do, and while I’ve done a few there are lots more that I’d like to do some day.&lt;/p&gt;
&lt;p&gt;It’s a wonderful feeling to augment the printer with parts made by the printer itself.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;RockNRoll&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#RockNRoll&quot; class=&quot;heading-ref&quot;&gt;RockNRoll&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/rocknroll.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Flipping over the printer to access the electronics apartment is a huge pain.
There’s a very cool &lt;a href=&quot;https://github.com/VoronDesign/VoronUsers/tree/master/printer_mods/LoganFraser/TridentInvertedElectronics&quot;&gt;inverted electronics bay mod&lt;/a&gt; for Trident printers, but it’s a tall ask for me to redo &lt;em&gt;all&lt;/em&gt; the wiring at this point.&lt;/p&gt;
&lt;p&gt;But then I found the simple &lt;a href=&quot;https://mods.vorondesign.com/detail/tiIhFDTh9tHJY0JNJK9A&quot;&gt;RockNRoll&lt;/a&gt; mod that allows you to easily tilt the printer.
Just having the rockers doesn’t work as the center of gravity is too high for the Trident, but with &lt;a href=&quot;https://www.printables.com/model/638776-voron-rocknroll-mod-stilts/files&quot;&gt;these additional stilts&lt;/a&gt; it works great.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Removable-panels&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Removable-panels&quot; class=&quot;heading-ref&quot;&gt;Removable panels&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/magnetic_top.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Having to screw and unscrew the panels when modding or messing around with the toolhead got old fast.
Therefore I made the panels easily removable by using magnets and snap latches.&lt;/p&gt;
&lt;p&gt;The top is completely magnetic using the &lt;a href=&quot;https://mods.vorondesign.com/detail/GawFyXN2J0rlSecCAJUpZQ &amp;quot;Magnetic panels with Magnet Inserts&amp;quot;&quot;&gt;Magnetic panels with Magnet Inserts&lt;/a&gt; mod and is very easy to remove and replace.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/corner_jig.jpg&quot;&gt;
&lt;figcaption&gt;Installation of the corner magnets.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I played around with the amazing &lt;a href=&quot;https://mods.vorondesign.com/detail/9Rdnf5vD2oaJLmR7BpAuQ &amp;quot;Printable snap latches for 2020 extrusion&amp;quot;&quot;&gt;snap latches&lt;/a&gt; mod to hold the panels together:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/snap_latch.jpg&quot;&gt;
&lt;figcaption&gt;The latch closes with a very satisfying thud.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;But they’re a bit cumbersome to lock and unlock, so I compromised and used the latches in the middle of the side panels and used magnets for the corners:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/magnetic_side.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I also made the bottom panel magnetic using &lt;a href=&quot;https://mods.vorondesign.com/detail/mRnQfulRJGN3pfPBbSjzA &amp;quot;Bottom Panel Mag Clip&amp;quot;&quot;&gt;the bottom panel mag clip&lt;/a&gt; mod:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/magnetic_bottom.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Necessary?
No—but it feels nice.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Clicky-clack-door&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Clicky-clack-door&quot; class=&quot;heading-ref&quot;&gt;Clicky-clack door&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/clicky_door.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I really didn’t like the stock doors on the printer.
I was planning to use the same magnetic and/or latch system for the front door, but I realized it would be very bothersome compared to a door you can swing open.&lt;/p&gt;
&lt;p&gt;Luckily I found the &lt;a href=&quot;https://github.com/tanaes/whopping_Voron_mods/tree/main/clickyclacky_door&quot;&gt;Clicky-Clack Fridge Door&lt;/a&gt; mod that replaces the split panels with a full panel door and that can swing open, provides a better seal than the stock doors, and can easily be removed.
It may not win any beauty awards, but it sure is functional.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Angry-cam&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Angry-cam&quot; class=&quot;heading-ref&quot;&gt;Angry cam&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/angrycam_mount.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The mod I most appreciate is probably having an integrated camera.
It’s great to be able to just glance at my phone to see how the print is going, instead of having to go down to the basement to check.&lt;/p&gt;
&lt;p&gt;I used the &lt;a href=&quot;https://mods.vorondesign.com/detail/RYpQW53mtem8Nj1JKqiSQ&quot;&gt;Angry CAM USB&lt;/a&gt; mod to mount a small camera module in the front of the printer, above the doors.
The camera itself showed up in Mainsail and to my relief it worked immediately.
To configure resolution you can alter &lt;code&gt;crowsnest.conf&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[cam 1]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;mode: ustreamer                         # ustreamer - Provides mjpg and snapshots. (All devices)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;resolution: 2592x1944                   # widthxheight format
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;max_fps: 15                             # If Hardware Supports this it will be forced, otherwise ignored/coerced.
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To see what resolution and fps the camera supports, you can take a look in &lt;code&gt;~/printer_data/logs/crowsnest.log&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I used the MJPEG IP Camera integration to get the feed into Home Assistant, using &lt;code&gt;http://192.168.1.32/webcam/?action=stream&lt;/code&gt; as the URL and made a quick dashboard for the printer:&lt;/p&gt;
&lt;figure&gt;&lt;img width=&quot;80%&quot; alt=&quot;&quot; src=&quot;/images/trident/ha_galileo.png&quot;&gt;
&lt;figcaption&gt;Can you smell what the rock is cooking?!
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I should probably rework this and all other Home Assistant dashboards one day…&lt;/p&gt;
&lt;p&gt;The mount works well, but the camera is far from perfect.
It’s good enough for checking in on the print, but a more clear view would’ve been nice.
The focus isn’t working well, the colors are off, and I don’t see the whole build plate.
Worse, the toolhead often covers up the print so I can’t see if it’s still printing well.&lt;/p&gt;
&lt;p&gt;I won’t do anything about it right now, but in the future I’ll probably try to replace it with something else.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Smart-filament-sensor&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Smart-filament-sensor&quot; class=&quot;heading-ref&quot;&gt;Smart filament sensor&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/btt_with_spool.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Bed adhesion and first layer problems are annoying, but they can be mitigated by watching the first layer go down and if it goes badly you don’t lose that much time.&lt;/p&gt;
&lt;p&gt;Something much more annoying is when the filament tangles.
According to the internet it “should never happen”, but it has happened with four different spools from different manufacturers and it sucks when the print fails multiple hours in.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/tangled_spool.jpg&quot;&gt;
&lt;figcaption&gt;See this? This damned spool ruined 4 prints in a row for me.
It’s not a real knot, but it’s tangled hard enough that the extruder couldn’t pull it free, and it started to grind down the filament instead of extruding it.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Fed up, I ordered Bigtreetech’s &lt;a href=&quot;https://www.3djake.com/bigtreetech/smart-filament-sensor-v20&quot;&gt;Smart Filament Sensor V2.0&lt;/a&gt; that can detect both running out of filament and these “knotted” spools.&lt;/p&gt;
&lt;p&gt;There are some &lt;a href=&quot;https://www.printables.com/model/683859-bigtreetech-smart-filament-sensor-v20-mounting-bra&quot;&gt;nice mounts&lt;/a&gt; for it, but finding a good mounting point was difficult.
I ended up moving the spool to the side of the printer, and routing the cable through the back panel:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/btt_mounted.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;One difficulty was that the wire was just a tad too short. I got it to reach, but just barely.
I couldn’t route the cables to make the underside pretty… But meh.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/btt_octopus.jpg&quot;&gt;
&lt;figcaption&gt;The Octopus has dedicated ports for the two BTT connectors.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;To setup Klipper I used this code:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[filament_switch_sensor filament_sensor_switch]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;switch_pin: ^PG12
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pause_on_runout: True
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;insert_gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    M117 Insert detected
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;runout_gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    M117 Runout detected
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    SET_DISPLAY_TEXT MSG=&quot;Runout detected!&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[filament_motion_sensor filament_sensor_motion]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;switch_pin: ^PG13
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;detection_length: 10 # ellis recommends to start at 10mm, could maybe adjust this?
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;extruder: extruder
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pause_on_runout: True
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;insert_gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    M117 Insert detected
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;runout_gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    M117 Runout detected
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    SET_DISPLAY_TEXT MSG=&quot;Runout detected!&quot;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You also need proper &lt;code&gt;PAUSE&lt;/code&gt;/&lt;code&gt;RESUME&lt;/code&gt; macros.
I just copied the macros from &lt;a href=&quot;https://ellis3dp.com/Print-Tuning-Guide/articles/useful_macros/pause_resume_filament.html&quot;&gt;Ellis’ print tuning guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I tested it by holding the filament during the print, trying to simulate a knot in the filament.
This worked, but damn was it HARD.
The extruder really does have force behind it.&lt;/p&gt;
&lt;p&gt;Since installing the sensor it has already saved multiple prints.
For sure a huge quality-of-life improvement, and feels like a must-have.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Flex-plate-stops&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Flex-plate-stops&quot; class=&quot;heading-ref&quot;&gt;Flex plate stops&lt;/a&gt;&lt;/h2&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/flexplate_endstop.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/flexplate_endstop.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/flexplate_endstop2.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/flexplate_endstop2.jpg&quot;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Aligning the flex plate isn’t too much of a pain, but adding some &lt;a href=&quot;https://www.printables.com/model/411428-voron-24-flex-plate-stops&quot;&gt;flex plate stops&lt;/a&gt; makes the process easier.&lt;/p&gt;
&lt;p&gt;To fit it at the back I removed the now unused z-endstop (I use Tap instead).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Gridfinity-mounts&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Gridfinity-mounts&quot; class=&quot;heading-ref&quot;&gt;Gridfinity mounts&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/top_gridfinity_mounts.jpg&quot;&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/bottom_gridfinity_mounts.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve been slowly easing into &lt;a href=&quot;https://www.youtube.com/watch?v=ra_9zU-mnl8&quot;&gt;Gridfinity&lt;/a&gt;—a free and open organization system.
So naturally I wanted to add some some holders to the printer.&lt;/p&gt;
&lt;p&gt;I used a combination of &lt;a href=&quot;https://www.printables.com/model/175108-gridfinity-holder-for-voron-printers-2020-extrusio&quot;&gt;top&lt;/a&gt; and &lt;a href=&quot;https://www.printables.com/model/431489-gridfinity-mount-for-2020-extrusions-voron-printer&quot;&gt;bottom&lt;/a&gt; holders.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Meshed-panels&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Meshed-panels&quot; class=&quot;heading-ref&quot;&gt;Meshed panels&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/meshes.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Adding &lt;a href=&quot;https://www.printables.com/model/455437-voron-trident-mesh-skirts&quot;&gt;meshes for the panels&lt;/a&gt; might be one of the prettiest mods you can do—and I think it’s very pretty—but that’s not why I did it.
I added it as a safety measure against my kids (or me) inserting something like a screwdriver inside the electronics while the printer is running.&lt;/p&gt;
&lt;p&gt;I didn’t do any fancy filament swapping prints, I just printed the meshes and glued them onto the backs of the panels.
It works.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Galileo-2&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Galileo-2&quot; class=&quot;heading-ref&quot;&gt;Galileo 2&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/galileo_6.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I replaced the Clockwork 2 extruder with the &lt;a href=&quot;https://github.com/JaredC01/Galileo2&quot;&gt;Galileo 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This wasn’t exactly needed, I just thought it would be fun as building the Clockwork was one of the most interesting parts of the build, and this &lt;a href=&quot;https://www.engineeringclicks.com/planetary-gears/&quot;&gt;planetary gears&lt;/a&gt; thing looked pretty interesting.
And the FOMO kicked in as I was following the discussion online, with people hyping about it but not being able to find a kit.
So when I happened to find one I couldn’t help myself.&lt;/p&gt;
&lt;p&gt;I was planning to make a separate post only about the build, but the build was surprisingly very quick so I think it works if I include it in this blog post.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/galileo_1.jpg&quot;&gt;
&lt;figcaption&gt;I was worried about the quality of my printed parts, but they fit well.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/galileo_2.jpg&quot;&gt;
&lt;figcaption&gt;The planetary gears.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/galileo_3.jpg&quot;&gt;
&lt;figcaption&gt;Time to shove the motor into place.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/galileo_5.jpg&quot;&gt;
&lt;figcaption&gt;The drive gear is installed.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The only difficulty I encountered when assembling the extruder itself was to align the drive gear.
It touched the printed part, and I was worried my prints came out all wrong.
The manual says that you can push down the carrier shaft, but I had to disassemble it and realign it before attaching the motor.
After the reassembly it luckily aligned properly.&lt;/p&gt;
&lt;p&gt;There were no issues mounting the extruder onto Tap or into the Stealthburner either.
The LDO toolhead PCB fit without having to use spacers, although closing the lid was &lt;em&gt;very&lt;/em&gt; tight.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/galileo_mounted.jpg&quot;&gt;
&lt;figcaption&gt;Galileo 2 fits well on the printed Tap.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The biggest pain point was the wiring management (yet again).
The drag chain mount on the Galileo 2 is higher up than on the Clockwork 2, which meant I had to pull through more wiring to be able reach the PCB.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/galileo_undo_wiring.jpg&quot;&gt;
&lt;figcaption&gt;Opening up the drag chains to pull through more wiring.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I really don’t enjoy opening up the drag chains, it’s just a huge pain.
The next time I need to mess with it, I’ll probably go Canbus or &lt;a href=&quot;https://lab4450.com/product/ldo-nitehawk-sb/&quot;&gt;Nitehawk&lt;/a&gt; and get rid of the annoying chains.&lt;/p&gt;
&lt;p&gt;I’ve seen some people complaining that they’ve lost some y-travel, but I don’t understand why.
For me the range has been unchanged.&lt;/p&gt;
&lt;p&gt;The big question is, &lt;strong&gt;does it print better?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It’s a difficult question, because I don’t really know.
Maybe it does, but I didn’t make any test prints to really compare.
But it’s not an extreme improvement like some people online made me to believe.
It’s more an incremental improvement, and the Clockwork 2 would honestly be good enough for me.&lt;/p&gt;
&lt;p&gt;I do miss the latch of the Clockwork 2, but I don’t think I’ll switch back right now.
Even small improvements to extrusion quality is nice.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Purge-bucket-CNC-Tap&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Purge-bucket-CNC-Tap&quot; class=&quot;heading-ref&quot;&gt;Purge bucket &amp;amp; CNC Tap&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The kit comes with a steel brush and references the &lt;a href=&quot;https://github.com/VoronDesign/VoronUsers/tree/master/orphaned_mods/edwardyeeks/Decontaminator_Purge_Bucket_%26_Nozzle_Scrubber&quot;&gt;Decontaminator Purge Bucket &amp;amp; Nozzle Scrubber&lt;/a&gt; mod that I was quite excited for.&lt;/p&gt;
&lt;p&gt;Unfortunately, Tap decreases the range of motion for the toolhead so that the nozzle no longer can reach back behind the bed:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/noise_y_reach.jpg&quot;&gt;
&lt;figcaption&gt;This is as far back the nozzle can go. As you can see, it doesn’t reach the (now unused) z endstop, and there’s no room for a purge bucket / nozzle scrubber.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There are some things I could do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Ditch Tap and use Klicky probe instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replace the printed Tap with a CNC Tap.&lt;/p&gt;
&lt;p&gt;The Chaoticlab CNC Voron Tap v2 should save around 4mm in the y-axis while Vitalii’s version should save around 1.4mm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.vorondesign.com/community/howto/clee/sensorless_xy_homing.html&quot;&gt;Sensorless XY homing&lt;/a&gt; might also give back some range.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Moving the bed is a theoretical solution, but that seems difficult to me.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I bought a &lt;a href=&quot;https://www.3djake.com/chaoticlab/cnc-voron-tap-black-v2&quot;&gt;Chaoticlab CNC Voron Tap&lt;/a&gt;, but had I known about the sensorless homing I might have tried that out first.&lt;/p&gt;
&lt;p&gt;Installation was straightforward, I just had to be mindful of these things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Grease the rails.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Apply threadlocker to the screws.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I had to switch the wiring in the Tap–PCB cable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;~!PG15&lt;/code&gt; instead of &lt;code&gt;^PG15&lt;/code&gt; in the probe config.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But—and here’s the big but—it’s not compatible with LDO’s X/Y Endstop PCB board:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/tap_x_endstop.jpg&quot;&gt;
&lt;figcaption&gt;There’s nothing to press the X Endstop switch anymore.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;To make this work I’ll have to add an X Endstop to the toolhead (there’s a dedicated mount for it), which is fine.
There’s a X Endstop connector in the toolhead PCB…
But I don’t see how to get that signal out from LDO’s breakout board in the electronics compartment (it takes it from the X/Y Endstop PCB).&lt;/p&gt;
&lt;p&gt;That feels like a lot of effort…
And I told myself I would not drag more wires through the drag chain, so I gave up on the mod for now.
I’ll revisit this when I move to an umbilical setup, where I plan to move the X and Y endstops anyway to get rid of the drag chains.&lt;/p&gt;
&lt;p&gt;But that’s a larger project for the future, at the moment I’m content.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back in no time.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;last words of William S. Burroughs
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/section&gt;
</content></entry><entry><title>The eBook for &apos;Why Cryptocurrencies?&apos; is now available for free</title><id>http://jonashietala.se/blog/2024/02/19/the_ebook_for_why_cryptocurrencies_is_now_available_for_free/index.html</id><updated>2024-06-27T07:48:59+00:00</updated><link href="https://www.jonashietala.se/blog/2024/02/19/the_ebook_for_why_cryptocurrencies_is_now_available_for_free" rel="alternate"/><published>2024-02-19T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The eBook for my book &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;Why Cryptocurrencies?&lt;/a&gt; is now &lt;a href=&quot;https://buy.whycryptocurrencies.com/download&quot;&gt;available for free&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It’s &lt;a href=&quot;/blog/2020/04/29/my_book_why_cryptocurrencies_is_done/&quot;&gt;been almost 4 years&lt;/a&gt; since the &lt;a href=&quot;https://whycryptocurrencies.com/toc.html&quot;&gt;web version&lt;/a&gt; was done, and &lt;a href=&quot;/blog/2021/05/31/why_cryptocurrencies_is_now_available_in_print/&quot;&gt;3 since the physical copy was available&lt;/a&gt;…
Which can hardly be called a success.&lt;/p&gt;
&lt;p&gt;Things happened, so let’s do a quick retrospective to, maybe, learn something.&lt;/p&gt;
&lt;section id=&quot;The-project-is-done&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-project-is-done&quot; class=&quot;heading-ref&quot;&gt;The project is done&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m very good at putting myself down and to focus on the negative parts to the expense of the positive.&lt;/p&gt;
&lt;p&gt;I need to learn to take a step back and appreciate the good things I do, and even though it took a log time the book project is now &lt;strong&gt;&lt;strong&gt;completely done&lt;/strong&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;No matter how you look at it, actually finishing a large project such as self-publishing a book should be seen as a success.
Sure, it took a lot longer than I wanted to wrap it up, but I &lt;em&gt;finished it&lt;/em&gt;, and finishing a large project is an accomplishment in itself.&lt;/p&gt;
&lt;p&gt;I’ve had this project hanging over me like a dark cloud, painfully aware that it’s &lt;em&gt;almost&lt;/em&gt; done—and has been &lt;em&gt;almost&lt;/em&gt; done for years—continually increasing my stress levels.
But now, I can finally let it go.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let it go, let it go&lt;br&gt;
Can’t hold it back anymore&lt;br&gt;
Let it go, let it go&lt;br&gt;
Turn away and slam the door
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YVVTZgwYwVo&quot;&gt;Frozen&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;(I prefer the &lt;a href=&quot;https://www.youtube.com/watch?v=BKCsFB5bPz8&quot;&gt;Swedish version&lt;/a&gt; of the song.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;I-made-it-more-difficult-for-myself-than-it-had-to-be&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#I-made-it-more-difficult-for-myself-than-it-had-to-be&quot; class=&quot;heading-ref&quot;&gt;I made it more difficult for myself than it had to be&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Despite reading countless advice to “focus on content”, and to “choose a simple solution”, I added too much complexity and was a tad too ambitious.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I used a &lt;a href=&quot;/blog/2020/05/03/how_i_wrote_my_book_using_pollen/&quot;&gt;non-standard generator&lt;/a&gt;, with no native eBook or PDF generation support.&lt;/p&gt;
&lt;p&gt;While generating a PDF was easy (it’s basically a copy of the PDF for the printed book), generating a nice-looking and functional EPUB took a bunch of time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I was very particular with the typesetting and styling.&lt;/p&gt;
&lt;p&gt;The result looks great, but styling the web version, the printed version, and then (re)style the epub took a &lt;em&gt;lot&lt;/em&gt; of extra time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I wanted to take payments in crypto, so before I made the eBook I made my own &lt;a href=&quot;https://github.com/bitpal/bitpal&quot;&gt;cryptocurrency payment processor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The project suffered hard from ridiculous scope-creep, and it was far from “just accept a payment”
(which was done the first week…).
It’s also yet-another “almost finished” project I want to revisit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In hindsight, the error is obvious.
I should’ve written the book in an existing solution that would generate the website, epub, and PDF with minimal intervention from my side.
Or at the very least I should’ve setup the epub and PDF generation from the start, instead of rushing the writing and leave the rest until later (leading to a bunch of extra work).&lt;/p&gt;
&lt;p&gt;The idea was to make the eBook purchasable with an assortment of crypto—and I did have that for a while—but I really should’ve focused on finishing the eBook in a timely manner instead.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Burnout-procrastination-and-losing-faith&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Burnout-procrastination-and-losing-faith&quot; class=&quot;heading-ref&quot;&gt;Burnout, procrastination, and losing faith&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While I certainly bit off more than I could chew, I faced other challenges during the project:&lt;/p&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
I got burnt out, hard.
&lt;/li&gt;
&lt;li&gt;
I’m an expert-level procrastinator.
&lt;/li&gt;
&lt;li&gt;
My faith in the cryptocurrency community continued to dwindle.
&lt;/li&gt;
&lt;li&gt;
We got another kid—twice! Now we have three.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wrote a &lt;a href=&quot;/blog/2023/03/14/battling_burnout/&quot;&gt;separate post about my burnout&lt;/a&gt;, no need to rehash the details of that unpleasant experience again here.
With the burnout (and the depression that tagged along), my heavy procrastination, and the arrival of two kids, maybe the surprising thing isn’t that it took so long, but that I got anything done at all?&lt;/p&gt;
&lt;section id=&quot;Procrastination-is-about-doing-the-wrong-thing&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Procrastination-is-about-doing-the-wrong-thing&quot; class=&quot;heading-ref&quot;&gt;Procrastination is about doing the wrong thing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Wait a minute you might think; how can this person claim to procrastinate when he’s done so many other things?&lt;/p&gt;
&lt;p&gt;It’s true that I’ve spent a lot of time to do many other things, while neglecting the book project.
But to me procrastination isn’t about doing nothing, it’s about doing things with less priority.&lt;/p&gt;
&lt;p&gt;For example, instead of finishing the book project I &lt;a href=&quot;/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit/&quot;&gt;rewrote the blog in Rust&lt;/a&gt;, refactored it to &lt;a href=&quot;/blog/2024/02/02/blogging_in_djot_instead_of_markdown/&quot;&gt;use Djot instead of Markdown&lt;/a&gt; (despite Markdown working just fine), &lt;a href=&quot;/series/voron_trident/&quot;&gt;built a 3D printer&lt;/a&gt;, and spent tons of time &lt;a href=&quot;/series/t-34/&quot;&gt;designing my own keyboard layout&lt;/a&gt;…&lt;/p&gt;
&lt;p&gt;These are really fun, cool, and even sort-of productive things.
But they weren’t the things I &lt;em&gt;should&lt;/em&gt; have prioritized, which in the logic of procrastination makes them &lt;em&gt;very appealing&lt;/em&gt; to my brain.&lt;/p&gt;
&lt;p&gt;I don’t know how to stop procrastinating.
The best strategy I’ve found is to try to harness it by directing it towards something productive (such as exploring a new programming language), and accept the fact that progress on other project will sometimes slow down.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;I-still-believe-in-the-potential-of-crypto&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#I-still-believe-in-the-potential-of-crypto&quot; class=&quot;heading-ref&quot;&gt;I still believe in the potential of crypto….&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I still firmly believe that cryptocurrencies has an amazing unrealized potential—and I still stand behind the majority of my arguments &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;in the book&lt;/a&gt;, where I focus on what cryptocurrencies can be useful for.
In many ways I think the arguments of digital cash are even stronger today than when I started writing the book some 5 years ago.&lt;/p&gt;
&lt;p&gt;But I severely underestimated the negative effect “fast money” had on the cryptocurrency community, and how the focus completely shifted from cryptocurrencies being used to buy things in the real world, to just rampant speculation and get-rich-schemes.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/lasereyes-min.jpg&quot;&gt;
&lt;figcaption&gt;The LaserEyes Bitcoin campaign exemplifies everything I loath about crypto.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;10 years ago, if you asked people what the point of Bitcoin was, they would’ve said that it’s a new form of money that you can send instantly and very cheaply to anyone in the world, without handing it over to a third-party.&lt;/p&gt;
&lt;p&gt;But today people will point at the newly approved Bitcoin ETF, that Bitcoin has tons of institutional investments, and that it’s a “great Store of Value”.
Which is all only an euphemism for speculation and a desire to get rich.&lt;/p&gt;
&lt;p&gt;Thinking about it makes me tired and sad, and drains me of the energy and makes me want to distance myself from the space, rather than try to improve it.
The point of crypto was to improve things for regular people, not &lt;em&gt;this&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;How’s that for a recommendation for &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;my book&lt;/a&gt; that extols the virtues of crypto? :)&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Main-takeaways&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Main-takeaways&quot; class=&quot;heading-ref&quot;&gt;Main takeaways&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to finish a similar project in a reasonable amount of time, I’d say these are the biggest tips I have:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Fight complexity and scope-creep.&lt;/p&gt;
&lt;p&gt;Focus on the content of the book—cut down everything else.
Except for marketing, but how to do that competently is a riddle you’ll have to solve yourself.&lt;/p&gt;
&lt;p&gt;If I had a setup that could generate a web version, an EPUB, and a PDF from the start the eBook would’ve been completed years ago.
But now I let things come between, and time runs quickly when that happens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find a way to stay motivated.&lt;/p&gt;
&lt;p&gt;I for one love to start projects, but finishing them is tough.
If you find a project that you’re &lt;em&gt;really&lt;/em&gt; passionate about then you’ll drastically increase the chance for success.
And even if you do, if the project takes a long time then it can still be challenging to get the project over the finish line.&lt;/p&gt;
&lt;p&gt;External positive feedback is also helpful, even though I believe the best motivation comes from within.&lt;/p&gt;
&lt;p&gt;What gave me the last push was that I told myself in very stern words that I have to finish this before I can start my next project.
I’ve done this multiple times with varying levels of success, but this time my brain seemed to listen.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sometimes shit out of your control happens.&lt;/p&gt;
&lt;p&gt;I was going to add “don’t get burnt out” as an item, but I should know that it’s not something you easily avoid.&lt;/p&gt;
&lt;p&gt;Acceptance that it sometimes take longer is good.
I try to tell myself that it’s not a disaster just because it takes a bit longer than initially planned.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><title>How I did the layout for my self-published book</title><id>http://jonashietala.se/blog/2024/02/17/how_i_did_the_layout_for_my_self-published_book/index.html</id><updated>2026-04-27T10:16:42+00:00</updated><link href="https://www.jonashietala.se/blog/2024/02/17/how_i_did_the_layout_for_my_self-published_book" rel="alternate"/><published>2024-02-17T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is a rundown of how I typeset and laid out my self-published book for the &lt;a href=&quot;https://whycryptocurrencies.com/toc.html&quot;&gt;web version&lt;/a&gt;, the &lt;a href=&quot;https://buy.whycryptocurrencies.com/download&quot;&gt;EPUB version&lt;/a&gt;, and the &lt;a href=&quot;https://whycryptocurrencies.com/#print&quot;&gt;printed version&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I was planning to include many more details, but the project took a lot longer than planned so I’ve forgotten some things.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Web-page&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Web-page&quot; class=&quot;heading-ref&quot;&gt;Web page&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I started by creating the book in a web format.
It’s a static site generator that simply outputs HTML with some custom CSS styling to make it look pretty.
I wrote a separate post on &lt;a href=&quot;/blog/2020/05/03/how_i_wrote_my_book_using_pollen/&quot;&gt;how I wrote a book with Pollen&lt;/a&gt;, check it out if you want more details.&lt;/p&gt;
&lt;p&gt;As I’ve become more proficient with CSS, I would’ve used Flexbox and Grid instead of floats and other hacks.
Still, I’m quite pleased with how it looks even though I’d rather not look at the implementation.&lt;/p&gt;
&lt;p&gt;I’m absolutely no CSS or design wizard, I just spent quite some time tweaking until I ended up with something decent (I guess design is simple, but not easy).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;EPUB&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#EPUB&quot; class=&quot;heading-ref&quot;&gt;EPUB&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The initial plan was to use Pollen to generate both the web and eBook version from the same source.
This is supported in Pollen by branching in the output functions, for example this emphasis function &lt;a href=&quot;https://docs.racket-lang.org/pollen/fourth-tutorial.html&quot;&gt;from the tutorial&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;emph&lt;/span&gt; . &lt;span class=&quot;variable other pollen&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;current-poly-target&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    [&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;txt&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;**&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; ,@&lt;span class=&quot;variable other pollen&quot;&gt;elements&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;**&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    [&lt;span class=&quot;keyword control pollen&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;txexpr&lt;/span&gt; &amp;#39;&lt;span class=&quot;variable other pollen&quot;&gt;strong&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;empty&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;]&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately, I didn’t do this from the beginning and I wanted to create an EPUB after the book, and all the functions, had already been made.&lt;/p&gt;
&lt;p&gt;I could of course go back and modify them all, but it was much faster to just branch the repo and modify the webpage until it produced a valid EPUB.
Hardly ideal, but it actually wasn’t as bad as it may sound.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies/src/branch/epub3&quot;&gt;epub3 branch&lt;/a&gt; on Codeberg for the complete source for the EPUB.&lt;/p&gt;
&lt;section id=&quot;Creating-an-EPUB&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Creating-an-EPUB&quot; class=&quot;heading-ref&quot;&gt;Creating an EPUB&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are many EPUB generators out there, but those I tried didn’t produce very pretty books (in many cases the results were quite bad).
But an EPUB is merely XHTML with some extra files, so it’s fairly straightforward to create one by hand.&lt;/p&gt;
&lt;p&gt;There is an &lt;a href=&quot;https://www.w3.org/TR/epub-33/&quot;&gt;EPUB 3 specification&lt;/a&gt; one can reference, but I’ve always found that it’s much easier to get going by &lt;a href=&quot;https://github.com/IDPF/epub3-samples&quot;&gt;looking at examples&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For my book, this is how the file structure ended up in the EPUB:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;├── META-INF
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── container.xml
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   └── encryption.xml
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── OEBPS
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── content.opf
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── main.css
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── toc.ncx
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── fonts
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   │   └── ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── images
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   │   ├── emission-rates-fallback.png
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   │   ├── emission-rates.svg
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   │   ├── generals.png
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   │   └── ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── how_do_cryptocurrencies_work.xhtml
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   └── ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;└── mimetype
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;.epub&lt;/code&gt; file itself is just a zip of the above, with the mimetype first in the archive:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;!/bin/bash&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; _ebook/&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;zip&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;X0&lt;/span&gt; why_cryptocurrencies.epub mimetype&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;zip&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;Xur9D&lt;/span&gt; why_cryptocurrencies.epub &lt;span class=&quot;keyword operator regexp quantifier shell&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to take a closer look, you can &lt;a href=&quot;https://buy.whycryptocurrencies.com/download&quot;&gt;download the EPUB for free&lt;/a&gt; and unzip it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;mimetype&lt;/code&gt; contains the mimetype (without a trailing newline):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;application/epub+zip
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The entry-point to everything is the &lt;code&gt;META-INF/container.xml&lt;/code&gt; file that simply redirects us to &lt;code&gt;OEBPS/content.opf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;xml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight xml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag preprocessor xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;entity name tag xml&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;1.0&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;container&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;1.0&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;urn:oasis:names:tc:opendocument:xmlns:container&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;rootfiles&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;rootfile&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;full-path&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;OEBPS/content.opf&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;application/oebps-package+xml&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;rootfiles&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We don’t have to use the &lt;code&gt;OEBPS/&lt;/code&gt; directory, but most of the examples I looked at used it so I ran with it.
Maybe it’s some kind of standard or something, I don’t know.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;content.opf&lt;/code&gt; contains what you think it does: all the content for the book:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;xml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight xml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag preprocessor xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;entity name tag xml&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;1.0&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;UTF-8&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;http://www.idpf.org/2007/opf&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;unique-identifier&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;pub-identifier&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;3.0&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name namespace xml&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;entity other attribute-name xml&quot;&gt;&lt;span class=&quot;punctuation separator namespace xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;en&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;metadata&lt;/span&gt; &lt;span class=&quot;entity other attribute-name namespace xml&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;entity other attribute-name xml&quot;&gt;&lt;span class=&quot;punctuation separator namespace xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;dc&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;http://purl.org/dc/elements/1.1/&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name namespace xml&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;entity other attribute-name xml&quot;&gt;&lt;span class=&quot;punctuation separator namespace xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;opf&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;http://www.idpf.org/2007/opf&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; There are other meta fields you want to set, this is just an example &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag namespace xml&quot;&gt;dc&lt;/span&gt;&lt;span class=&quot;entity name tag xml&quot;&gt;&lt;span class=&quot;punctuation separator namespace xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Why Cryptocurrencies?&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag namespace xml&quot;&gt;dc&lt;/span&gt;&lt;span class=&quot;entity name tag xml&quot;&gt;&lt;span class=&quot;punctuation separator namespace xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;refines&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;#title&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;title-type&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;main&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; Sets the cover page that shows up in EPUB readers &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;cover&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images-cover-front&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; With EPUB 3 you can also create fixed layouts.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             My EPUB tries to mimic the reflowable web version,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             although you could bundle both in the same EPUB file if you wanted to. &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;rendition:layout&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;reflowable&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;rendition:flow&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;scrolled-doc&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;manifest&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; The .ncx file is a deprecated file that EPUB 3 readers should ignore,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             but it may be included to help EPUB 2 readers understand the file.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             Instead the &amp;lt;spine&amp;gt; element is used to describe the reading order of the book.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             I won&amp;#39;t describe the file more, if you&amp;#39;re curious download the epub and crack it open. &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;ncx&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;toc.ncx&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;application/x-dtbncx+xml&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;style&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;main.css&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;text/css&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; Every chapter in the book has its own .xhtml file. &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;how_do_cryptocurrencies_work&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;how_do_cryptocurrencies_work.xhtml&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;application/xhtml+xml&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; All images needs its own entry too. &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images-generals&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images/generals.png&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;image/png&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; This is the cover reference defined earlier in the &amp;lt;metadata&amp;gt; section. &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images-cover-front&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images/cover/front.png&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;image/png&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;cover-image&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; Svg images should specify a png fallback. &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images-emission-rates&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images/emission-rates.svg&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;image/svg+xml&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;fallback&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images-emission-rates-fallback&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images-emission-rates-fallback&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;images/emission-rates-fallback.png&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;image/png&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; And the fonts needs to be specified as well. &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;century_supra_a_regular&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;fonts/century_supra_a_regular.woff2&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;media-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;application/font-woff&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;manifest&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;spine&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;toc&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;ncx&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; The spine contains the default reading order of chapters
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             (or &amp;quot;items&amp;quot;, they don&amp;#39;t have to be chapters). &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;itemref&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;idref&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;coverpage&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;itemref&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;idref&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;titlepage&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;linear&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;yes&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;page-spread-left&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;itemref&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;idref&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;dedication&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;linear&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;yes&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;page-spread-right&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;itemref&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;idref&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;acknowledgements&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;linear&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;yes&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;page-spread-right&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;itemref&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;idref&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;toc&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;page-spread-right&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;itemref&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;idref&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;about_the_book&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;page-spread-right&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;itemref&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;idref&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;eli5&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;page-spread-right&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;spine&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s also font “encryption” via &lt;code&gt;encryption.xml&lt;/code&gt; (which is only obfuscation) that I had to use because of the license of the fonts I use, but generally it’s not needed.&lt;/p&gt;
&lt;p&gt;And that’s basically all an EPUB is.
I used a very hacky &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies/src/branch/epub3/ebookify&quot;&gt;Python script&lt;/a&gt; to move the files into position, generate the spine, image items, and the other stuff I alluded to above.&lt;/p&gt;
&lt;p&gt;Why did I write that in Python instead of in Racket, which the rest of the book made with?
I really have no idea…&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Styling&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Styling&quot; class=&quot;heading-ref&quot;&gt;Styling&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I had an incredibly frustrating experience trying to style the EPUB to match the web version, with matching spacing, typeset, sidenotes, and the rest.
It felt that whatever I tried, every reader would just ignore all the styling and fall back to their own and—in my opinion—horrible appearance.&lt;/p&gt;
&lt;p&gt;I even gave up on the eBook for a time because of it.&lt;/p&gt;
&lt;p&gt;But then I noticed I had made an EPUB 2 instead of an EPUB 3, and with the newer version all styling worked with little modification.
This of course depends on the EPUB reader, but there’s not much I can do about that:&lt;/p&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/crypto_readers/ReadEra.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_readers/ReadEra.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/crypto_readers/eBoox.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_readers/eBoox.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/crypto_readers/lithium.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_readers/lithium.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Different Android readers (ReadEra, eBoox, and Lithium) renders the EPUB very differently.
Unfortunately, the EPUB won’t look great on all readers.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Validating&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Validating&quot; class=&quot;heading-ref&quot;&gt;Validating&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the EPUB created, you should validate it.
The commonly recommended &lt;a href=&quot;http://validator.idpf.org/&quot;&gt;idpf validator&lt;/a&gt; seems to be down, I instead used &lt;a href=&quot;https://github.com/w3c/epubcheck&quot;&gt;epubcheck&lt;/a&gt; I found on github.&lt;/p&gt;
&lt;p&gt;Turns out I had a few errors in my EPUB:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ java -jar epubcheck.jar ~/code/why_cryptocurrencies/_ebook/why_cryptocurrencies.epub
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Check finished with errors
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Messages: 2 fatals / 2183 errors / 2 warnings / 0 infos
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And this was after I had made a bunch of corrections. Sigh…&lt;/p&gt;
&lt;p&gt;Fixing them was annoying and time consuming, but it wasn’t hard. Most of them were easily fixed by updating the templates and tag generation within Pollen.&lt;/p&gt;
&lt;p&gt;Errors I ran into includes xhtml being more strict than html, so I couldn’t nest an &lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt; inside a &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, leading to a nice big refactor of my sidenote generation code.&lt;/p&gt;
&lt;p&gt;Another error pointed out that I had to provide &lt;code&gt;.png&lt;/code&gt; fallbacks for all &lt;code&gt;.svg&lt;/code&gt; images.
With the &lt;a href=&quot;https://fishshell.com/&quot;&gt;fish shell&lt;/a&gt; and &lt;a href=&quot;https://inkscape.org/&quot;&gt;inkscape&lt;/a&gt; you can mass convert images like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; file &lt;span class=&quot;keyword&quot;&gt;in&lt;/span&gt; *.svg
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;function&quot;&gt;inkscape&lt;/span&gt; -w &lt;span class=&quot;number&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;$file&lt;/span&gt; --export-filename &lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;function&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;$file&lt;/span&gt; .svg&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;-fallback.png
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then specify the fallback in &lt;code&gt;content.opf&lt;/code&gt; as shown before.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Physical-book&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Physical-book&quot; class=&quot;heading-ref&quot;&gt;Physical book&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The initial idea was, again, to use Pollen to create the book.
I wanted to use Pollen to generate Latex that could produce the PDF I wanted.&lt;/p&gt;
&lt;p&gt;But that’s not the route I went with.
Similar to how it was a big challenge to get Pollen to produce an EPUB version in conjunction to a regular HTML version, making it produce a Latex variant was a big task.
In addition, making Latex reproduce my sidenote styling and placement wasn’t at all straightforward (maybe I just suck at Latex).&lt;/p&gt;
&lt;p&gt;I instead laid out the PDF with &lt;a href=&quot;https://www.adobe.com/products/indesign.html&quot;&gt;InDesign&lt;/a&gt;.
It required more manual tweaks that I really didn’t enjoy, but on the flip side it was very easy to make manual adjustments to get the layout &lt;em&gt;just&lt;/em&gt; right.&lt;/p&gt;
&lt;section id=&quot;XML-importer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#XML-importer&quot; class=&quot;heading-ref&quot;&gt;XML importer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Of course, we don’t want to manually copy-paste the whole book, that would be silly.
InDesign has an XML importer that we can use to import the book, and if we setup styles to automatically apply to certain elements (such as &lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt; sidenotes) you get quite a lot of help.&lt;/p&gt;
&lt;p&gt;Yes, it’s buggy and not well documented, but it’s still a life-saver.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_indesign/references.png&quot;&gt;
&lt;figcaption&gt;I had to style the references manually because the importer messed them up…
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Styles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Styles&quot; class=&quot;heading-ref&quot;&gt;Styles&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To work effectively with InDesign I found that effective use of styles is a must.
The most important part of laying out my book was getting sizing and spacing right, and to do that you setup styles for the different cases and apply them (mostly to paragraphs).&lt;/p&gt;
&lt;p&gt;Lots of people love to rag on CSS, but CSS is very powerful and it’s relatively simple to for example style a list, with proper spacing before, after, and between elements and text just the way you want it.
With InDesign this wasn’t nearly as straightforward, and I ended up with several styles I had to apply depending on the surrounding context:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_indesign/list_paragraph_styles.png&quot;&gt;
&lt;figcaption&gt;I ended up with quite a few paragraphs related to lists. The first and last paragraph needed special handling because the spacing was slightly different in order to play nice with other styles.
Then there’s “multi” that contains multiple paragraphs in one list item, nested lists, and different types of lists…
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;All this just to get consistent spacing for my various lists.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_indesign/styled_lists_spread.png&quot;&gt;
&lt;figcaption&gt;I think the lists look nice and are very readable.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Lots-of-manual-tweaks&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Lots-of-manual-tweaks&quot; class=&quot;heading-ref&quot;&gt;Lots of manual tweaks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most of the time what I did in InDesign is read through the book to make small adjustments.
I adjusted sidenote placements, tweaked styles here and there, adjusted page breaks to balance pages, adjusted paragraphs, added index references… And then I did it all over again.&lt;/p&gt;
&lt;p&gt;Yes it’s time consuming and annoying, but also weirdly therapeutic.
I could satisfy my need for perfection by nudging text boxes around until the end of time.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_indesign/boxes_laid_out.png&quot;&gt;
&lt;figcaption&gt;Who needs therapy when you can lay out boxes?
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Printed-books-have-certain-expectations&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Printed-books-have-certain-expectations&quot; class=&quot;heading-ref&quot;&gt;Printed books have certain expectations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you upload a book on a website, or even if you create an EPUB, you can almost do whatever you want and it’ll probably be fine.
But printed books has certain expectations that should be followed.&lt;/p&gt;
&lt;p&gt;For example how a new chapter or section should start on a new page to the right, and leave the left page blank if needed.
Or how chapters and sections next to page numbers on the bottom can help you navigate a technical book such as mine.
These are things you don’t really notice, unless you come across a book without them.
(Fiction has other expectations because you don’t jump around when you read.)&lt;/p&gt;
&lt;p&gt;One thing that’s easy to forget about in the internet age the &lt;strong&gt;index&lt;/strong&gt; you can find at the end of many books.
It’s designed to help you easily find things in the book, sort of like a curated search engine, but on paper.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/crypto_indesign/index.png&quot;&gt;
&lt;figcaption&gt;A correctly structured index is invaluable. Mine at least exists.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Designing a good index is hard, because it’s not about listing all keywords in the book.
It’s about anticipating the needs of the reader, so someone searching for “Bitcoin” may be redirected to the chapter &lt;a href=&quot;https://whycryptocurrencies.com/how_do_cryptocurrencies_work.html&quot;&gt;How do cryptocurrencies work?&lt;/a&gt;, even though Bitcoin isn’t singled out in the chapter (it discuses cryptocurrencies in general).&lt;/p&gt;
&lt;p&gt;The index also acts as a sort of overview of what topics are discussed.
(Aren’t you curious why &lt;a href=&quot;https://whycryptocurrencies.com/undesirable_businesses.html&quot;&gt;Dakota Skye is mentioned in the index&lt;/a&gt;?)&lt;/p&gt;
&lt;p&gt;This seems difficult to do well—and I probably failed hard—but I tried.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;What-Id-do-differently&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#What-Id-do-differently&quot; class=&quot;heading-ref&quot;&gt;What I’d do differently&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If I would write a book again, I would try to do what I wanted to in the first place: generate all versions from a single source.&lt;/p&gt;
&lt;p&gt;I wouldn’t have used &lt;a href=&quot;https://docs.racket-lang.org/pollen/index.html&quot;&gt;Pollen&lt;/a&gt;.
While it feels really nice to be able to inject code anywhere in your markup, having to maintain 3 different outputs with every function you write is a bit much.&lt;/p&gt;
&lt;p&gt;Instead I’d try some kind of standard markup format with preexisting EPUB and PDF generation.
I could still set it up to have custom transformations, but it would be so much easier to work with compared to programming the generation completely by myself.&lt;/p&gt;
&lt;p&gt;Working with InDesign was actually fine, but keeping the different versions in sync was difficult, so it would still be beneficial to cut it out from the process if possible.&lt;/p&gt;
&lt;p&gt;But I’d still want to do the layout myself.
It didn’t feel difficult, I mostly enjoyed the process, and I think the result was quite good.&lt;/p&gt;
&lt;p&gt;The boxes don’t nudge themselves you know?&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Printing Hextraction for my kids</title><id>http://jonashietala.se/blog/2024/02/09/printing_hextraction_for_my_kids/index.html</id><updated>2024-06-27T07:54:09+00:00</updated><link href="https://www.jonashietala.se/blog/2024/02/09/printing_hextraction_for_my_kids" rel="alternate"/><published>2024-02-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/hextraction_session.jpg&quot;&gt;
&lt;figcaption&gt;A session of Hextraction, a 3D printed board game.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I did it.
I made something actually useful with &lt;a href=&quot;/series/voron_trident/&quot;&gt;my 3D printer&lt;/a&gt; instead of just tinkering with it.&lt;/p&gt;
&lt;p&gt;I printed &lt;a href=&quot;https://www.playhextraction.com/&quot;&gt;Hextraction&lt;/a&gt;, a very cool 3D printed board game for my kids—and they love it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.playhextraction.com/&quot;&gt;Hextraction&lt;/a&gt; is a gamified marble run, where you place tiles and drop balls in order to reach the end without getting yeeted off the board.
It’s kind of hard to explain it in text, so if you’re still confused just watch the video from the creator.
He’s hilarious:&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=Iqz7ZDdP25A&quot;&gt;https://www.youtube.com/watch?v=Iqz7ZDdP25A&lt;/a&gt;
&lt;p&gt;(The first 20 seconds should give you a good idea of what the game look likes.)&lt;/p&gt;
&lt;section id=&quot;Keep-it-simple&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Keep-it-simple&quot; class=&quot;heading-ref&quot;&gt;Keep it simple&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While I &lt;strong&gt;&lt;strong&gt;&lt;strong&gt;love&lt;/strong&gt;&lt;/strong&gt;&lt;/strong&gt; boardgames, I printed this game for my kids to enjoy.
Because they’re still young at 6 and 3 years (our 1-year old have to wait) I had to keep the game simpler than I’d personally like.&lt;/p&gt;
&lt;p&gt;You see, &lt;a href=&quot;https://www.playhextraction.com/&quot;&gt;Hextraction&lt;/a&gt; doesn’t only use regular tiles that directs the balls, they also have special effect tiles that have special rules.
For example, with the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Teleport%20Tile-856643&quot;&gt;Teleport Tile&lt;/a&gt; you can restart your ball from another location or with the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Clone%20Tile-855930&quot;&gt;Clone Tile&lt;/a&gt; you’re supposed to roll another ball from that same tile.
The mind boggles with cool and interesting plays with these kinds of tiles…&lt;/p&gt;
&lt;p&gt;But they all have their own specific rules that you have to remember or read on a rules card.
Having to constantly be reminded of rules isn’t really fun, and our kids can’t read Swedish let alone English yet, so unfortunately the special effect tiles must be ignored for now.&lt;/p&gt;
&lt;p&gt;Another thing I’ve avoided are the “launcher” tiles that will launch the balls in the air, so you can try to jump over tiles or onto the goals.
Although they look fun—and they would be perfect for my boys—I dislike the idea of launching balls to our 1-year old crawling on the floor.&lt;/p&gt;
&lt;p&gt;Other than that the rules we use are very simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Place a tile (out of a hand of 3)
&lt;/li&gt;
&lt;li&gt;
Drop a ball
&lt;/li&gt;
&lt;li&gt;
Draw a new tile
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And if ever 3 balls (or more) get stuck on a single tile, you’re allowed to remove one tile that the balls are touching.&lt;/p&gt;
&lt;p&gt;(Oh, if a ball happens to bounce into a goal, that’s ok and part of the game!)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Boards&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Boards&quot; class=&quot;heading-ref&quot;&gt;Boards&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before getting into the tiles—which is the meat of the game—let me first address the board, which is the structure you place your tiles into.&lt;/p&gt;
&lt;p&gt;There’s an &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Game%20Boards-856439&quot;&gt;official board&lt;/a&gt; you can use, but I really didn’t like it for one major reason:
the balls can easily drop off the board, onto the table and roll down to the floor where our 1-year old might find and try to eat them.&lt;/p&gt;
&lt;p&gt;Luckily, &lt;a href=&quot;https://www.playhextraction.com/&quot;&gt;Hextraction&lt;/a&gt; advertises itself as a hackable game, and Thangs user &lt;a href=&quot;https://thangs.com/designer/Inaudable&quot;&gt;Inaudible&lt;/a&gt; has created two wonderful alternative boards for us to enjoy:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
The &lt;a href=&quot;https://thangs.com/designer/Inaudable/3d-model/Super%20Fancy%20Remix%20of%20the%20Hextraction%20Game%20Board-955813&quot;&gt;super fancy remix&lt;/a&gt; with full gutters, variable size, ball holders and more.
&lt;/li&gt;
&lt;li&gt;
A &lt;a href=&quot;https://thangs.com/designer/Inaudable/3d-model/Modular%20Hextraction%20Board%21-972454&quot;&gt;modular board&lt;/a&gt; you can rebuild into smaller and larger weirdly shaped boards.
&lt;/li&gt;
&lt;/ol&gt;
&lt;section id=&quot;Modular-board&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Modular-board&quot; class=&quot;heading-ref&quot;&gt;Modular board&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/modular_board.jpg&quot;&gt;
&lt;figcaption&gt;The modular board.
I failed a little with my color selection as the two darker gray colors are way too similar.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I started with the &lt;a href=&quot;https://thangs.com/designer/Inaudable/3d-model/Modular%20Hextraction%20Board%21-972454&quot;&gt;modular board&lt;/a&gt; because I thought it would be nice to be able to modify it later, but mostly it was because it had just been released and my monkey brain thought “newer = better”.&lt;/p&gt;
&lt;p&gt;I think the design is very cool.
You can rearrange the board into cool and weird shapes, and add “blockers” right in the middle where no tiles can go.
But we only use it as a regular board, because rearranging it is a bit of a chore, and overkill for my kids.&lt;/p&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
The mind boggles with the possibilities.
&lt;/li&gt;
&lt;li&gt;
Easily repairable if something breaks.
&lt;/li&gt;
&lt;li&gt;
Can be made in a cool varying colorscheme.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
It was easy to break the goals (they act like levers). I broke three of them.
&lt;/li&gt;
&lt;li&gt;
It’s not so easy to remove the balls from the gutters.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Super-fancy-remix&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Super-fancy-remix&quot; class=&quot;heading-ref&quot;&gt;Super fancy remix&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/fancy_board.jpg&quot;&gt;
&lt;figcaption&gt;The super fancy board remix.
I again failed with my color selection, as this is two (very similar) shades of brown.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Because I’m not a reasonable person, I also printed the &lt;a href=&quot;https://thangs.com/designer/Inaudable/3d-model/Super%20Fancy%20Remix%20of%20the%20Hextraction%20Game%20Board-955813&quot;&gt;super fancy remix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While you can make the board larger, everything is glued together so once the choice is made you’ll have to live with it.
I made it the same size as the other board, because… I don’t know really.&lt;/p&gt;
&lt;p&gt;While the board is less exciting than the modular one, I greatly appreciate the integrated gutters that funnel the balls to the center of the board.
There are some extra things, like dice and ball holders, but it’s not something we use.&lt;/p&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Feels more robust.
&lt;/li&gt;
&lt;li&gt;
Good gutters that funnels all the balls into one place.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Doesn’t have the same coolness factor or flexibility as the modular board.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Which-board-should-you-print&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Which-board-should-you-print&quot; class=&quot;heading-ref&quot;&gt;Which board should you print?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If I had printed this for myself, I would’ve gone for the &lt;a href=&quot;https://thangs.com/designer/Inaudable/3d-model/Modular%20Hextraction%20Board%21-972454&quot;&gt;modular board&lt;/a&gt; and played around with other layouts.
But for my kids and our use-case, I think the &lt;a href=&quot;https://thangs.com/designer/Inaudable/3d-model/Super%20Fancy%20Remix%20of%20the%20Hextraction%20Game%20Board-955813&quot;&gt;super fancy remix&lt;/a&gt; is better because it’s a bit more robust and the fully integrated gutters are superior.&lt;/p&gt;
&lt;p&gt;You can of course print them both…
But that require quite some time and material, so just pick one.
The gutters are a must in my opinion, so I’d rather choose one of these boards over the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Game%20Boards-856439&quot;&gt;original board&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Tiles&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Tiles&quot; class=&quot;heading-ref&quot;&gt;Tiles&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/pile_o_tiles.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The fun part of &lt;a href=&quot;https://www.playhextraction.com/&quot;&gt;Hextraction&lt;/a&gt; is the tiles, and there are lots of different tiles.
At first I thought it’d be a challenge to find fun and interesting tiles when I’ve disqualified many of the most fun ones, but there were plenty of tiles for me and my kids to enjoy.&lt;/p&gt;
&lt;section id=&quot;Path-tiles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Path-tiles&quot; class=&quot;heading-ref&quot;&gt;Path tiles&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/path_tiles.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Honestly, a lot of the times when playing the game one of the most appreciated tiles to draw is just a regular tile.
Around half of the tiles we use are these basic path tiles.
It’s tempting to go nuts with the special tiles, but you need basic tiles to make the reasonable.
If everything is special, then nothing is.&lt;/p&gt;
&lt;p&gt;The original creator provides a &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Basic%20Tiles-856511&quot;&gt;good selection of basic tiles&lt;/a&gt;, most with short descriptive names; the DC, DIC, X, J, S, Z, Asterisk, and Peace tiles.
I’ve added the &lt;a href=&quot;https://thangs.com/designer/BowTy%20Productions/3d-model/Tile%20-%20K-979132&quot;&gt;K tile&lt;/a&gt;, &lt;a href=&quot;https://thangs.com/designer/BowTy%20Productions/3d-model/Tile%20-%20V-979180&quot;&gt;V tile&lt;/a&gt;, &lt;a href=&quot;https://thangs.com/designer/BowTy%20Productions/3d-model/Tile%20-%20W-979185&quot;&gt;W tile&lt;/a&gt;, &lt;a href=&quot;https://thangs.com/designer/theethetree/3d-model/Xc%20Tile%20-%20Hextraction-871018&quot;&gt;Xc tile&lt;/a&gt;, &lt;a href=&quot;https://thangs.com/designer/BowTy%20Productions/3d-model/Tile%20-%20Triangle-979174&quot;&gt;Triangle tile&lt;/a&gt;, &lt;a href=&quot;https://thangs.com/designer/BowTy%20Productions/3d-model/Tile%20-%20Scissors-979168&quot;&gt;Scissors tile&lt;/a&gt;, &lt;a href=&quot;https://thangs.com/designer/BowTy%20Productions/3d-model/Tile%20-%20Rectangle-979162&quot;&gt;Rectangle tile&lt;/a&gt;, and some &lt;a href=&quot;https://thangs.com/designer/jaceubs/3d-model/Hextraction%20Reroute%20Tiles-902024&quot;&gt;Reroute tiles&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Secret-tiles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Secret-tiles&quot; class=&quot;heading-ref&quot;&gt;Secret tiles&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We had some mixed feelings about the secret tiles.
On one hand it’s great fun to place a tile that only you know how it works,
but on the other hand the ball tends to get stuck inside them quite often, making the “3-ball then destroy the tile” rule difficult to keep track of.&lt;/p&gt;
&lt;p&gt;So I replaced them with &lt;a href=&quot;https://www.printables.com/model/594135-hextraction-alt-secret-tiles&quot;&gt;alternative secret tiles&lt;/a&gt; that never blocks a ball path:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/opened_secret_tiles.jpg&quot;&gt;
&lt;figcaption&gt;This is the tiles before I glued the lid on. Although it wasn’t supposed to, the ball sometimes got stuck in the crossed out tile, so we threw that one away.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I also used the &lt;a href=&quot;https://www.printables.com/model/496253-secret-lid-inverted-upgrade-for-hextraction-game-n&quot;&gt;inverted secret lid&lt;/a&gt; to make the lid (much) easier to print well.&lt;/p&gt;
&lt;aside class=&quot;warn&quot;&gt;
&lt;p&gt;If you want to use the standard secret tiles, please note that the holes for the lids are too shallow for a few of them.
See &lt;a href=&quot;https://www.printables.com/model/496288-fixed-secret-hextraction-mystery-tiles/files&quot;&gt;this link&lt;/a&gt; and &lt;a href=&quot;https://thangs.com/designer/timothyjackman/3d-model/Fixed%20Hextraction%20Secret%20Flipper%20Tile-884171&quot;&gt;this link&lt;/a&gt; for fixes.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Trap-tiles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Trap-tiles&quot; class=&quot;heading-ref&quot;&gt;Trap tiles&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/trap_tiles.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The trap tiles add quite a lot of depth to the game.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/regular_trap_tiles.jpg&quot;&gt;
&lt;figcaption&gt;Of the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Trap%20Tiles%20-%20Double%20and%20Triple%20Trap-837140&quot;&gt;standard trap tiles&lt;/a&gt;, the double one is the best IMHO.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Traps are interesting because they allow you to block paths, allowing you to throw a wrench into your opponents plans at a crucial time.
This often leads to the players having to route around existing paths, without blocking them off completely.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/angry_crab.jpg&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;https://thangs.com/designer/hpalinux/3d-model/Hextraction%20Tile%3A%20Angry%20Crab-911792&quot;&gt;Angry Crab&lt;/a&gt; acts as a trap for the middle, and is released from the sides.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/newtons_cradle.jpg&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://www.printables.com/model/636021-hextraction-newtons-cradle-tile-no-supports-remix&quot;&gt;Newton’s Cradle&lt;/a&gt; is an interesting one. Depending on how you orient the tile, it can act as a trap (that you can release from the other side) or as a regular tile.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://www.printables.com/model/636021-hextraction-newtons-cradle-tile-no-supports-remix&quot;&gt;Newton’s Cradle&lt;/a&gt; and the &lt;a href=&quot;https://thangs.com/designer/hpalinux/3d-model/Hextraction%20Tile%3A%20Angry%20Crab-911792&quot;&gt;Angry Crab&lt;/a&gt; are probably my two favorite tiles in the game.
I should print more of them.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Speed-bump-tiles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Speed-bump-tiles&quot; class=&quot;heading-ref&quot;&gt;Speed bump tiles&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/speed_bump_tiles.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;a href=&quot;https://thangs.com/designer/QTManygo/3d-model/Hextraction%20-%20Speed%20Bumps%20Tiles-903950&quot;&gt;speed bump tiles&lt;/a&gt; decreases the speed of the ball, trapping it if it’s moving too slow.
The issue is that the kids gets a bit too frustrated with them, so I’ve reduced the number of speed bump tiles in circulation.&lt;/p&gt;
&lt;p&gt;We still have three that we use, mostly because I like the educational aspect of the tiles (it’s physics!).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Flip-flop-tiles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Flip-flop-tiles&quot; class=&quot;heading-ref&quot;&gt;Flip-flop tiles&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/spinners.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Even though it can malfunction at times, the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Flip-Flop%20Tile-856502&quot;&gt;Flip-flop tile&lt;/a&gt; is great as it adds a small state machine to the game.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Misc-tiles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Misc-tiles&quot; class=&quot;heading-ref&quot;&gt;Misc tiles&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/pachinko.jpg&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Pachinko%20Tile-837138&quot;&gt;Pachinko tile&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I personally really enjoy the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Pachinko%20Tile-837138&quot;&gt;Pachinko tile&lt;/a&gt; as it’s a great way to add some more randomness.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/uwu_zoidberg.jpg&quot;&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Zoidberg%20Tile-856450&quot;&gt;Zoidberg&lt;/a&gt; and &lt;a href=&quot;https://thangs.com/designer/IceChes/3d-model/Hextraction%20-%20UwU%20Tile-903488&quot;&gt;UwU&lt;/a&gt; gives a face to Hextraction.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Because that level of randomness isn’t enough, the beautiful &lt;a href=&quot;https://thangs.com/designer/IceChes/3d-model/Hextraction%20-%20UwU%20Tile-903488&quot;&gt;UwU tile&lt;/a&gt; and the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Zoidberg%20Tile-856450&quot;&gt;Zoidberg tile&lt;/a&gt; acts as a random trap tile.
But they’re mostly traps.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/loop.jpg&quot;&gt;
&lt;figcaption&gt;A &lt;a href=&quot;https://thangs.com/designer/theethetree/3d-model/Hextraction%20Loop-de-loop%20tile-873977&quot;&gt;loop&lt;/a&gt;. You need speed if you want to get through this one.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I also threw in a &lt;a href=&quot;https://thangs.com/designer/theethetree/3d-model/Hextraction%20Loop-de-loop%20tile-873977&quot;&gt;loop&lt;/a&gt;, because it’s silly and it’s fun when you manage to get a ball through it.
It has the same pedagogical effect as a &lt;a href=&quot;https://thangs.com/designer/QTManygo/3d-model/Hextraction%20-%20Speed%20Bumps%20Tiles-903950&quot;&gt;speed bump tile&lt;/a&gt; while having a cooler effect.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/vortex.jpg&quot;&gt;
&lt;figcaption&gt;Who doesn’t love a good &lt;a href=&quot;https://thangs.com/designer/timothyjackman/3d-model/Hextraction%20Vortex%20Tile-886610&quot;&gt;vortex&lt;/a&gt;?
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Every marble run needs a vortex, and there’s the &lt;a href=&quot;https://thangs.com/designer/timothyjackman/3d-model/Hextraction%20Vortex%20Tile-886610&quot;&gt;Vortex tile&lt;/a&gt; to fill that spot in Hextraction.
I did have some issues getting it to print the tunnels correctly for my 10mm balls, but some filing took care of that issue.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/storage.jpg&quot;&gt;
&lt;figcaption&gt;Is there a better way to store balls than in a tile?
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;To store the balls I use &lt;a href=&quot;https://thangs.com/designer/andrewtho5942/3d-model/The%20Ultimate%20Hextraction%20Storage%20Box-885493&quot;&gt;The Ultimate Hextraction Storage Box&lt;/a&gt;.
It’s also a tile, although you &lt;del&gt;can’t&lt;/del&gt; shouldn’t play with it.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Make-the-game-yours&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Make-the-game-yours&quot; class=&quot;heading-ref&quot;&gt;Make the game yours&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The best thing about the game is that you can modify it to suit your needs.&lt;/p&gt;
&lt;p&gt;Don’t like a tile?
Hide it in a box or throw it in the trash.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/hextraction/unused_tiles.jpg&quot;&gt;
&lt;figcaption&gt;A box of unused Hextraction stuff.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;For example, I liked the idea of the &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Sozu%20Tile-856441&quot;&gt;Sozu tile&lt;/a&gt;, but I couldn’t get it to work consistently and having an extra rule of “first insert ball here” goes against our simplistic rules policy.&lt;/p&gt;
&lt;p&gt;We don’t use any of the special effects tiles, but you can (and should) try them out.
You can even make your own tiles, with your own silly rules.
The &lt;a href=&quot;https://thangs.com/designer/ZackFreedman/3d-model/Hextraction%20Cartoon%20Bomb%20Tile-856458&quot;&gt;bomb tile&lt;/a&gt; for example removes &lt;em&gt;all&lt;/em&gt; adjacent tiles when it’s removed, and the &lt;a href=&quot;https://thangs.com/designer/theethetree/3d-model/Hextraction%20-%20Angel%20Down%20Tile-902916&quot;&gt;angel down tile&lt;/a&gt; allows you to remove a trapped ball on any tile below.&lt;/p&gt;
&lt;p&gt;It’s a build your own adventure type of a game, and you can even design your own tiles (or boards, if you’re a madman).
If you’re like me and haven’t yet learned the dark CAD magic, there are &lt;a href=&quot;https://thangs.com/search/hextraction?scope=all&quot;&gt;lots of designs&lt;/a&gt; out there for you to include into your game.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Print-it-play-it&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Print-it-play-it&quot; class=&quot;heading-ref&quot;&gt;Print it, play it!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have a 3D printer lying around (or have a friend with one), I heavily recommend you to check out &lt;a href=&quot;https://www.playhextraction.com/&quot;&gt;Hextraction&lt;/a&gt;.
It’s a very cool and silly game, which works very well even for young kids with minor tweaks.
(To be honest, our 3-year old often uses it as a marble run. But that’s fine too.)&lt;/p&gt;
&lt;p&gt;And if you don’t have a 3D printer yet, go &lt;del&gt;buy&lt;/del&gt; &lt;a href=&quot;/series/voron_trident/&quot;&gt;build one&lt;/a&gt;!&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Blogging in Djot instead of Markdown</title><id>http://jonashietala.se/blog/2024/02/02/blogging_in_djot_instead_of_markdown/index.html</id><updated>2026-04-27T10:06:41+00:00</updated><link href="https://www.jonashietala.se/blog/2024/02/02/blogging_in_djot_instead_of_markdown" rel="alternate"/><published>2024-02-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;What if we weren’t chained to the past? What if we tried to create a light markup syntax that keeps what is good about Markdown, while revising some of the features that have led to bloat and complexity in the CommonMark spec?
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;John Macfarlane, &lt;a href=&quot;https://johnmacfarlane.net/beyond-markdown.html&quot;&gt;Beyond Markdown&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;I recently happened to see an offhand comment on &lt;a href=&quot;https://news.ycombinator.com/item?id=33867636&quot;&gt;Hacker News&lt;/a&gt; about a markup language called &lt;a href=&quot;https://github.com/jgm/djot&quot;&gt;Djot&lt;/a&gt;.
I don’t really have any large issues with the &lt;del&gt;Markdown&lt;/del&gt; &lt;a href=&quot;https://commonmark.org/&quot;&gt;CommonMark&lt;/a&gt; I use to generate the posts for this website, but my brain saw a chance to get sidetracked yet again, and here we are.&lt;/p&gt;
&lt;p&gt;The creator of &lt;a href=&quot;https://github.com/jgm/djot&quot;&gt;Djot&lt;/a&gt; is John MacFarlane, the same philosophy professor that also created &lt;a href=&quot;https://pandoc.org/&quot;&gt;Pandoc&lt;/a&gt; and &lt;a href=&quot;https://commonmark.org/&quot;&gt;CommonMark&lt;/a&gt;.
These might be two of the most influential projects in the markup space, so you’d get the feeling that maybe there’s something to this &lt;a href=&quot;https://github.com/jgm/djot&quot;&gt;Djot&lt;/a&gt; thing.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;The-devil-is-in-the-details&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-devil-is-in-the-details&quot; class=&quot;heading-ref&quot;&gt;The devil is in the details&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was going to give a few examples of what Djot looks like, but honestly, 95% of the Djot I write looks very similar to Markdown, with only minor differences.&lt;/p&gt;
&lt;p&gt;So what’s the point?&lt;/p&gt;
&lt;p&gt;The point is to try to take the good parts of CommonMark (the standard, unambiguous syntax specification for Markdown) and improve it in two ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Make it easier to parse.
&lt;/li&gt;
&lt;li&gt;
Extend the feature set.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’m sympathetic to the parsing problem, as it doesn’t sound that fun:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are 17 principles governing emphasis, for example, and these rules still leave cases undecided. The rules for list items and HTML blocks are also very complex. All of these rules lead to unexpected results sometimes, and they make writing a parser for CommonMark a complex affair. I despair, at times, of getting to a spec that is worth calling 1.0.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;John Macfarlane, &lt;a href=&quot;https://johnmacfarlane.net/beyond-markdown.html&quot;&gt;Beyond Markdown&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;For this alone I’d be willing to at least try Djot, but there are some added features I’d like to use.
It’s true that I probably won’t have much use for things like definition lists or math for my blog posts, but the native support for divs and the ability to add attributes to any element is something I’ve been missing.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Tools&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Tools&quot; class=&quot;heading-ref&quot;&gt;Tools&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Given that Djot is a relatively young project, I expected the tooling to be lacking.
There are things missing, but it wasn’t so bad for my use-case.&lt;/p&gt;
&lt;p&gt;I found a Djot Sublime Text grammar I can use for syntax highlighting the blog,
and there is Vim syntax highlighting in the &lt;a href=&quot;https://github.com/jgm/djot&quot;&gt;Djot repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(Sad for those who don’t use Vim I guess.)&lt;/p&gt;
&lt;p&gt;More annoying is that there’s no treesitter implementation for Djot.
This is unfortunate, as with treesitter for Markdown I get proper syntax highlighting inside code blocks and I have a general treesitter jump command that, for Markdown, jumps between headers with &lt;code&gt;]g&lt;/code&gt; and &lt;code&gt;[g&lt;/code&gt;.
(In Rust it jumps between structs, implementations, enums, and functions. It’s a general treesitter mapping.)&lt;/p&gt;
&lt;p&gt;Not a deal-breaker of course.
Using the Markdown treesitter for Djot works well enough for the time being.
(Maybe I need to explore how treesitter grammars work one day, and create one for Djot.)&lt;/p&gt;
&lt;p&gt;As for parsing I found &lt;a href=&quot;https://github.com/hellux/jotdown&quot;&gt;Jotdown&lt;/a&gt;, which is a Rust library with an API inspired by &lt;a href=&quot;https://crates.io/crates/pulldown-cmark&quot;&gt;pulldown-cmark&lt;/a&gt;, the library I use to parse CommonMark.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Abstracting-away-markup-parsing&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Abstracting-away-markup-parsing&quot; class=&quot;heading-ref&quot;&gt;Abstracting away markup parsing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I didn’t want to convert my existing Markdown files as I have more than 250 posts. (Yeah, I don’t know how that happened.)&lt;/p&gt;
&lt;p&gt;So to add Djot support I had to refactor my site generator a bit and support both Djot and Markdown parsing.
I’ve been lazy so this wasn’t as straightforward as I hoped; I had sprinkled calls to Markdown parsing all over the place.&lt;/p&gt;
&lt;p&gt;When I don’t really know where to begin unwinding such a mess, I like to begin by modeling the data types in the domain.
If I get the data modeling right, the rest has a tendency to fall into place fairly quickly.&lt;/p&gt;
&lt;p&gt;One of the things I love about Rust is the enums (or sum types for you fancy people) which makes it easy to model an “either this or that” type:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;Debug&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Copy&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Clone&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta enum rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type enum rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;entity name enum rust&quot;&gt;MarkupType&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Markdown&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Djot&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also add data to each variant, like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;Debug&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Clone&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta enum rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type enum rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;entity name enum rust&quot;&gt;Markup&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Markdown&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type rust&quot;&gt;String&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Djot&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type rust&quot;&gt;String&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is nice because now the type system prevents you from accidentally using the wrong format, which would be easier if you stored a &lt;code&gt;MarkupType&lt;/code&gt; and a &lt;code&gt;String&lt;/code&gt; separately.&lt;/p&gt;
&lt;p&gt;I did indeed store untagged data previously:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;PostItem&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Is this in markdown or already parsed to html?
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Wait, maybe it&amp;#39;s in djot!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;variable other member rust&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; String,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make this harder we should probably create a newtype for html as well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;Debug&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Clone&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; PartialEq&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Eq&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;Html&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;pub String&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then to parse the markup you can add a &lt;code&gt;parse&lt;/code&gt; method to &lt;code&gt;Markup&lt;/code&gt;, that delegates to the right parser:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;storage type impl rust&quot;&gt;impl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;entity name impl rust&quot;&gt;Markup&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;parse&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Result&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;Html&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Markdown&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;markdown_to_html&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;Self&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Djot&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;djot_to_html&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now posts can hold &lt;code&gt;Markup&lt;/code&gt; and &lt;code&gt;Html&lt;/code&gt; structs and we can rely on the compiler to ensure we don’t accidentally mix them:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;PostItem&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;variable other member rust&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; Html,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;variable other member rust&quot;&gt;markup&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; Markup,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Many other fields omitted..
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the right types in place the rest of the refactoring follows naturally.
Just hide any Markdown and Djot specific implementation behind these types, follow the compile errors, and you’re soon done.
Thinking and designing with types is usually a pleasure.&lt;/p&gt;
&lt;p&gt;(Yeah, maybe it’s not &lt;em&gt;quite&lt;/em&gt; that simple, but it’s a very helpful approach nevertheless.)&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;source for the website&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Customized-markup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Customized-markup&quot; class=&quot;heading-ref&quot;&gt;Customized markup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the blog I have some &lt;a href=&quot;/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit/#Markdown-transformations&quot;&gt;markup transformations&lt;/a&gt; I apply to Markdown.
This includes demoting headers, embedding bare YouTube links, transforming image collections, syntax highlighting, and more.&lt;/p&gt;
&lt;p&gt;It’s a bit hacky though.&lt;/p&gt;
&lt;section id=&quot;Epigraphs&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Epigraphs&quot; class=&quot;heading-ref&quot;&gt;Epigraphs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For example, I want to be able to turn a quote into an epigraph by wrapping it inside a div:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;epigraph&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;This is an epigraph&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But the CommonMark parser doesn’t process markdown inside html, so I &lt;a href=&quot;/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit/#Extending-pulldown_cmark&quot;&gt;added an attribute parser&lt;/a&gt; to wrap a quote in an epigraph:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight markdown&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta block-level markdown&quot;&gt;&lt;span class=&quot;markup quote markdown&quot;&gt;&lt;span class=&quot;punctuation definition blockquote markdown&quot;&gt;&amp;gt;&lt;/span&gt; This is an epigraph
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;{ :epigraph }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The implementation isn’t pretty, and only works for specific elements such as a blockquote.
But Djot has a built-in syntax for divs, so I can just write this to produce the same epigraph html output:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;epigraph&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup quote&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;&amp;gt; &lt;/span&gt;This is an epigraph&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Asides&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Asides&quot; class=&quot;heading-ref&quot;&gt;Asides&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I still need to do a bunch of transformations to reproduce existing functionality.&lt;/p&gt;
&lt;p&gt;For instance, I want html output like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;This is a notice&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There isn’t a native way to do this (other than inserting raw html, &lt;em&gt;ew&lt;/em&gt;).
For my own transformations the &lt;code&gt;div&lt;/code&gt; system works well as a starting point, so I can use this kind of input:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;note&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;This is a note
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then match on the &lt;code&gt;note&lt;/code&gt; class to transform the &lt;code&gt;div&lt;/code&gt; into &lt;code&gt;aside&lt;/code&gt;, and we’re done.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/hellux/jotdown&quot;&gt;Jotdown&lt;/a&gt;, like with &lt;a href=&quot;https://crates.io/crates/pulldown-cmark&quot;&gt;pulldown-cmark&lt;/a&gt;, transformations are made by transforming iterators over events.
Here I’m looking for &lt;code&gt;Event::Start(Container::Div, attrs)&lt;/code&gt; and &lt;code&gt;Event::End(Container::Div)&lt;/code&gt; (I ignore nesting).
Transforming with iterators instead of an AST structure is awkward, so keeping the transformations as small as possible is nice.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Images&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Images&quot; class=&quot;heading-ref&quot;&gt;Images&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I used the same &lt;code&gt;div&lt;/code&gt; syntax in Markdown to create collections of images:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight markdown&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta paragraph markdown&quot;&gt;::: Flex
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;/images/configura14/octree1.png{ height=300 }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;/images/configura14/octree2.png{ height=300 }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:::
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This would wrap the images in a flex container to display them side-by-side:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/configura14/octree1.png&quot;&gt;&lt;img height=&quot;300&quot; alt=&quot;&quot; src=&quot;/images/configura14/octree1.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/configura14/octree2.png&quot;&gt;&lt;img height=&quot;300&quot; alt=&quot;&quot; src=&quot;/images/configura14/octree2.png&quot;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figure&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;flex-50&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/configura14/octree1.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;300&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/configura14/octree1.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/configura14/octree2.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;300&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/configura14/octree2.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I (naturally) used to do this with Regex in a preprocessor step,
and had some fun adding attribute parsing.&lt;/p&gt;
&lt;p&gt;Now all I do is transform the &lt;code&gt;div&lt;/code&gt; to a &lt;code&gt;figure&lt;/code&gt; with the proper class.
Even something like this with references outside and attributes works, without any special handling on my end:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;flex&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup italic&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;![&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;markup link label&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;300&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup italic&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;![&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;markup link label&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;300&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:::&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup link url&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;markup link label&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation special&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;markup link url&quot;&gt;/images/configura14/octree1.png&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup link url&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup link url&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;markup link label&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation special&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;markup link url&quot;&gt;/images/configura14/octree2.png&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Yeah maybe I gloss over the gross implementation a little.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Blockquote-citations&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Blockquote-citations&quot; class=&quot;heading-ref&quot;&gt;Blockquote citations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Quotes are nice, but I want to be able to add author attribution to them sometimes.&lt;/p&gt;
&lt;p&gt;The html I want looks something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;With author attribution&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;John Doe&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With Markdown, I used custom attribute parsing to add author metadata:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight markdown&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta block-level markdown&quot;&gt;&lt;span class=&quot;markup quote markdown&quot;&gt;&lt;span class=&quot;punctuation definition blockquote markdown&quot;&gt;&amp;gt;&lt;/span&gt; With author attribution
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;{ author=John Doe }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I could’ve done the same thing with Djot, or piggyback on Djot’s general attribute parsing and match on that (the attributes go before the quote, but otherwise looks similar).&lt;/p&gt;
&lt;p&gt;But I got inspired by an ongoing discussion on the Djot repo about &lt;a href=&quot;https://github.com/jgm/djot/issues/198&quot;&gt;adding blockquote attribution support&lt;/a&gt; where this clean syntax was suggested:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup quote&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;&amp;gt; &lt;/span&gt;With author attribution&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup quote&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;&amp;gt; &lt;/span&gt;^ John Doe&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s no support for this yet, so I had to do the transformation myself.
But on the upside, by passing through the &lt;a href=&quot;https://github.com/hellux/jotdown&quot;&gt;Jotdown&lt;/a&gt; events after &lt;code&gt;^&lt;/code&gt; during the iteration transformation we can easily support links or other Djot markup in the author field.&lt;/p&gt;
&lt;p&gt;So this example:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup quote&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;&amp;gt; &lt;/span&gt;With author attribution&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup quote&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;&amp;gt; &lt;/span&gt;^ &lt;span class=&quot;markup&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;John Doe&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;markup link url&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;#&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string special&quot;&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;~&lt;/span&gt;31/1&lt;span class=&quot;punctuation delimiter&quot;&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Would produce:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;With author attribution&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;#&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;John Doe&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;31/1&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Other-transformations&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Other-transformations&quot; class=&quot;heading-ref&quot;&gt;Other transformations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are other transformations I do with Djot as well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;djot_to_html&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;djot&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Result&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Parser&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;djot&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Demote headers (eg h1 -&amp;gt; h2) and give them an &amp;quot;a&amp;quot; tag.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;TransformHeaders&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Convert standalone images to figures.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;AutoFigures&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Embed raw youtube links using iframes.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;EmbedYoutube&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Syntax highlighting.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;CodeBlockSyntaxHighlight&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;InlineCodeSyntaxHighlight&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Transform divs, such as asides and figures.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;DivTransforms&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Add a &amp;lt;footer&amp;gt; with author info to quotes.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;QuoteTransforms&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Warn if any broken links are detected.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;BrokenLink&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; context&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; body &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support type rust&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta path rust&quot;&gt;Renderer&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;default&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; body&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support type rust&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The ones I didn’t bring up in the blog are pretty similar to their corresponding Markdown implementation.
I’m not going to go through them in detail, see &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;the source code&lt;/a&gt; if you’re interested.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;The-future-is-bright&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-future-is-bright&quot; class=&quot;heading-ref&quot;&gt;The future is bright&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jgm/djot&quot;&gt;Djot&lt;/a&gt; is a young project but with the more expressive custom markup it has improved my blogging experience.
But more improvements are upcoming, with &lt;a href=&quot;https://github.com/jgm/djot/issues&quot;&gt;ongoing discussions&lt;/a&gt; on quite a few topics that would remove the need for many of my custom transformations, for example:&lt;/p&gt;
&lt;ol type=&quot;i&quot;&gt;
&lt;li&gt;
&lt;a href=&quot;https://github.com/jgm/djot/issues/198&quot;&gt;Native blockquote attributions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://github.com/jgm/djot/issues/87&quot;&gt;Auto block-level figures&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://github.com/jgm/djot/issues/31&quot;&gt;Captions for figures/tables&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://github.com/jgm/djot/issues/240&quot;&gt;Custom tags support&lt;/a&gt; (convert &lt;code&gt;div&lt;/code&gt; into &lt;code&gt;aside&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While I don’t currently use most of the added features compared to CommonMark, in the future I might start making use of the other types of lists (who doesn’t love a good list?) and footnotes might be a good addition to the more long-form blog posts I’ve been gravitating towards.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Complaints-about-Djot&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Complaints-about-Djot&quot; class=&quot;heading-ref&quot;&gt;Complaints about Djot&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve seen some people dismiss Djot because of its handling of sublists:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Exactly, the sublist newline stuff is a total nonstarter for me. Sorry, I guess I’ll run a markdown parser that takes an extra second or whatever to run.
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=33871415&quot;&gt;qbasic_forever&lt;/a&gt;
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;In Djot you have to surround a sublist with newlines. You can’t write this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup list&quot;&gt;- &lt;/span&gt;List
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;markup list&quot;&gt;- &lt;/span&gt;This is fine in Markdown, but not in Djot
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You have to do this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;djot&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight djot&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup list&quot;&gt;- &lt;/span&gt;List
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;markup list&quot;&gt;- &lt;/span&gt;This is fine in both Djot an Markdown
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It is indeeed more annoying at times, especially if you use the markup for smaller pieces of text, or use it to maintain a todo list with subtasks.
But for more long-form content I don’t think it’s a big deal (which is what Djot targets more I guess).&lt;/p&gt;
&lt;p&gt;Another complaint I’ve seen is that Djot doesn’t represent enough of an improvement compared to the different Markdown flavors to overtake them in popularity.
This is a fair take—but I don’t care if it ever dethrones Markdown/CommonMark/whatever.
It’s useful for me, and that’s all that really matters.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Smaller fixes</title><id>http://jonashietala.se/blog/2024/02/02/lets_build_a_voron_smaller_fixes/index.html</id><updated>2026-04-27T15:25:59+00:00</updated><link href="https://www.jonashietala.se/blog/2024/02/02/lets_build_a_voron_smaller_fixes" rel="alternate"/><published>2024-02-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been busy.
Busy printing stuff.&lt;/p&gt;
&lt;p&gt;Which is awesome, because one big worry I had was if I’d actually use the printer or just end up modding and tweaking it until the end of time.&lt;/p&gt;
&lt;p&gt;But of course, I’ve been slowly working through my large mods-I-want list.
My initial plan was to write one blog post about modding, but for space and sanity reasons I’ve decided to split it up.&lt;/p&gt;
&lt;p&gt;This post goes through a bunch of smaller fixes and mods I’ve done to the printer, and I’ll leave the more involved mods to later posts.&lt;/p&gt;
&lt;section id=&quot;Tweaks-tuning&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Tweaks-tuning&quot; class=&quot;heading-ref&quot;&gt;Tweaks &amp;amp; tuning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My plan was to take tuning seriously and go through all the tuning guides to get the printer to produce perfect prints.
But I didn’t have patience for that and I’ve only made some tweaks when the prints had noticeable defects.
Here are the major tweaks I’ve done since the last post:&lt;/p&gt;
&lt;section id=&quot;Bed-mesh-offset-in-one-corner&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Bed-mesh-offset-in-one-corner&quot; class=&quot;heading-ref&quot;&gt;Bed mesh offset in one corner&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It got pointed out to me in the &lt;a href=&quot;https://forum.vorondesign.com/threads/ldo-trident-250-complete-3d-printer-beginner.1089/&quot;&gt;VORON forum&lt;/a&gt; that I my right rear Y extrusion was a bit high.
The Trident has automatic bed leveling, but because the bed is only attached in three positions it can’t compensate for a difference in the rear that only has a single mount in the middle.
If you’re unlucky this might cause issues with bed adhesion.&lt;/p&gt;
&lt;p&gt;Turns out I’ve had some problems with bed adhesion.
Not a lot mind you, but enough to bother me on some trickier prints.
I’ve seen the offset on the corner go down to &lt;code&gt;-0.26&lt;/code&gt;, which is more than the standard &lt;code&gt;0.2&lt;/code&gt; layer height I use, so this might be the cause of some of the issues I’ve seen.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/wonky_offset.png&quot;&gt;
&lt;figcaption&gt;Before adjusting the right Y extrusion.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In the &lt;code&gt;voron_1_trident_questions&lt;/code&gt; channel on the VORONDesign Discord there was a pinned message on how to adjust this.
I ended up adjusting the front right Y extrusion upwards quite a bit to compensate for this.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/mesh_fixed.png&quot;&gt;
&lt;figcaption&gt;After adjusting the front right Y extrusion upwards.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The mesh still isn’t perfect (and it can sometimes look worse than the adjusted picture above), but it’s now a lot better and importantly the rear corners are much more level.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Bulging-corners&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Bulging-corners&quot; class=&quot;heading-ref&quot;&gt;Bulging corners&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One significant print issue I’ve had is bulging in the corners on overhangs:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/bulging_corners.jpg&quot;&gt;
&lt;figcaption&gt;Both edges round upwards and apart from being really ugly, they’ve caused a number of prints to fail when the nozzle has knocked loose pieces from the bed or has caused belts to skip.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/bulging_black.jpg&quot;&gt;
&lt;figcaption&gt;It’s really ugly.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Maybe it was overheating? But it happened consistently, with long layer times, with max fans, and for PLA/ABS/ASA.
Another idea was over extrusion, but I think that should’ve shown up in other places?&lt;/p&gt;
&lt;p&gt;Then I found the &lt;a href=&quot;https://ellis3dp.com/Print-Tuning-Guide/articles/troubleshooting/bulging.html&quot;&gt;Bulging&lt;/a&gt; section in Ellis’ Print Tuning Guide that made the issue disappear.
These were the changes I made:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Enable &lt;code&gt;external perimiter first&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
Set overhang &lt;code&gt;threshold for bridge flow&lt;/code&gt; to 0
&lt;/li&gt;
&lt;li&gt;
I also experimented with disabling overhangs specific settings completely (set &lt;code&gt;bridge speed and fan&lt;/code&gt; to 0 or the disable checkbox), but I’m uncertain how effectual that was compared to the other two settings.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these were specific to SuperSlicer, the slicer I use.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/bulging_nerf.jpg&quot;&gt;
&lt;figcaption&gt;These are two prints that show the difference between the settings.
The green is without the changes and white is with the changes.
Apart from the overhangs, the green printout looks pretty good, but the overhangs look terrible.
The white still has some defects, but it’s &lt;strong&gt;&lt;strong&gt;so&lt;/strong&gt;&lt;/strong&gt; much smoother.

&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Extruder-skipping&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Extruder-skipping&quot; class=&quot;heading-ref&quot;&gt;Extruder skipping&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I had printed for around 400 hours when the extruder suddenly started skipping.
At first it was just minor artifacts, but after a while prints started failing in major ways or refusing to extrude anything at all:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/bad_skip.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;My first idea was that I had messed up the tension in the extruder, so it no longer got a good grip on the filament.
(I had some major issues with loading filament at one time, and I started screwing around with everything I could think of.)&lt;/p&gt;
&lt;p&gt;But alas I couldn’t solve it with a quick-fix, so I had to open up the toolhead.
Which I should have done much sooner, because there were a bunch of broken filament stuck in the gears:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/cw2_dirty.jpg&quot;&gt;
&lt;figcaption&gt;One piece of broken filament inside the CW2, together with a bunch of dirt.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I really didn’t want to disassemble it because I was afraid of the effort to do so, but in the end it was just a few screws and the whole cleaning process took 10 min.
Building your own printer has some benefits, I should have more faith in the process.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;2mm-PTFE-between-extruder-and-hotend&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#2mm-PTFE-between-extruder-and-hotend&quot; class=&quot;heading-ref&quot;&gt;2mm PTFE between extruder and hotend&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There were a lot of leftovers after the build; nuts, screws, belts, etc.
But also an unused bag with “Teflon Tubing, 4x2mm”, which surely shouldn’t be completely unused?&lt;/p&gt;
&lt;p&gt;Turns out you’re supposed to use a tube with an inner diameter of 2mm between the extruder and hotend, but I had used the regular PTFE tube that had an inner diameter of 3mm.
This isn’t ideal and requires more retraction (which I didn’t compensate for), and it can cause stringing issues (which I had).&lt;/p&gt;
&lt;aside class=&quot;tip&quot;&gt;
&lt;p&gt;Don’t use a tube with an inner diameter of 2mm between the extruder and spool, the filament will get stuck due to friction.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;First-layer-woes&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#First-layer-woes&quot; class=&quot;heading-ref&quot;&gt;First layer woes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For a long time I was really happy with how my first layers looked and I could start a print and it would finish without issue most of the time.&lt;/p&gt;
&lt;p&gt;But sometimes I had these “blobs” that started collecting:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/filament_blob_printing.jpg&quot;&gt;
&lt;figcaption&gt;This is some extra filament that has been pushed around and gotten stuck on the print.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I couldn’t figure out where it was coming from. Overextrusion maybe, but i didn’t find any issues with it and this only happened in the beginning of the print.&lt;/p&gt;
&lt;p&gt;And later on I started to get &lt;em&gt;severe&lt;/em&gt; issues with bed adhesion where I felt lucky if a part stuck around long enough for the print to finish.
The first layer started to look garbage as well:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/clickfinity_bad.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/clickfinity_bad.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/clickfinity_bad2.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/clickfinity_bad2.jpg&quot;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;The worst part is, I didn’t think I had changed anything.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;In hindsight me fixing the &lt;a href=&quot;#Bed-mesh-offset-in-one-corner&quot;&gt;bed mesh offset&lt;/a&gt; might have been the cause my sudden problems.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;I tried a bunch of things; changing nozzle, recalibrating PA and EM, changing filament, and even replacing the extruder (more on that in a future post) yet the issue remained.&lt;/p&gt;
&lt;p&gt;What finally fixed it was recalibrating the &lt;a href=&quot;https://docs.vorondesign.com/build/startup/#z-offset-adjustment&quot;&gt;z offset&lt;/a&gt; and tuning &lt;a href=&quot;https://ellis3dp.com/Print-Tuning-Guide/articles/first_layer_squish.html&quot;&gt;first layer squish&lt;/a&gt; once more.
I’m not sure why I had to do this again (doesn’t Tap magically solve everything?), but now the first layer is pretty and the bed adhesion problems are almost completely gone.
(Some prints have a tendency to warp a little, but I guess it’s hard to get things perfect.)&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/clickfinity_good.jpg&quot;&gt;
&lt;figcaption&gt;Much better first layer!
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Mods&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Mods&quot; class=&quot;heading-ref&quot;&gt;Mods&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are some smaller mods from the LDO kit I hadn’t gotten around to installing, and some other small mods that fixed some annoyances I’ve had.&lt;/p&gt;
&lt;section id=&quot;Handles&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Handles&quot; class=&quot;heading-ref&quot;&gt;Handles&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/handles.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The kit includes some very nice handles you can install.
But unfortunately they cover up the top panel so you have to remove the handles before you can remove the panel—a gigantic pain.&lt;/p&gt;
&lt;p&gt;So I ended up printing some &lt;a href=&quot;https://mods.vorondesign.com/detail/EAM1ZiQJCUzXznvOA767w&quot;&gt;sturdy handles&lt;/a&gt; instead.
They’re really large comparatively, but they get the job done.
I haven’t had that much use for them yet, but I felt obliged installing them since some kind of handles came with the kit.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;LED-mounts&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#LED-mounts&quot; class=&quot;heading-ref&quot;&gt;LED mounts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There were no instructions on how to install the LEDs, so I taped them on top of the included extrusions covers.
Turns out you were supposed to print a bunch of &lt;a href=&quot;https://github.com/VoronDesign/VoronUsers/blob/master/printer_mods/eddie/LED_Bar_Clip/LED_Bar_Clip_Misumi_version2.stl&quot;&gt;LED mounts&lt;/a&gt; to get the LEDs pointing inwards towards the print for better lighting:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/led_old.jpg&quot;&gt;
&lt;figcaption&gt;Before the LED strips were mounted flat.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/leds_installed.jpg&quot;&gt;
&lt;figcaption&gt;Now they’re tilted inwards and have shields to direct the light towards the build plate.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Longer-spool-holder&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Longer-spool-holder&quot; class=&quot;heading-ref&quot;&gt;Longer spool holder&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/longer_holder.jpg&quot;&gt;
&lt;figcaption&gt;The stock spool holder to the left, a longer one I printed to the right.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I ran into the surprising issue that some spools were too wide for the stock spool holder (3DJake’s filament for example).
So I replaced it with a &lt;a href=&quot;https://mods.vorondesign.com/detail/wWS3pc510oGqxGo0awsFKA&quot;&gt;longer one&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the future I should probably replace it with a &lt;a href=&quot;https://mods.vorondesign.com/detail/VjlccbeeOuH5iax4AFHA&quot;&gt;top mounted spool holder&lt;/a&gt;, but I got lazy when I saw I didn’t have the required M5 hardware.
Maybe another day.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Bowden-tube-routing&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Bowden-tube-routing&quot; class=&quot;heading-ref&quot;&gt;Bowden tube routing&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/bowden_tube_routing.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I had some issues with the bowden tube getting stuck behind or under the cable chain, so I tried the &lt;a href=&quot;https://mods.vorondesign.com/detail/8CxQeqS1lXhlGphwkyqh7g&quot;&gt;bowden tube guide&lt;/a&gt; to keep it away.
It was difficult to find a route that worked well. Depending on the mount position it had a tendency to cause a bend in the tube that drastically increased the friction on the filament, which I suspect was the cause for some prints failing.&lt;/p&gt;
&lt;p&gt;I also use the &lt;a href=&quot;https://github.com/Diyshift/3D-Printer/tree/main/Trident%20Noodle&quot;&gt;Trident noodle&lt;/a&gt; that’s made to prevent the tube from colliding with the roof of the printer, and this combination works very well.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Display-mount&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Display-mount&quot; class=&quot;heading-ref&quot;&gt;Display mount&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/display.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The display mounts I got from the print-it-forward service wasn’t compatible with the screen I got, so I had to hold it together with tape.&lt;/p&gt;
&lt;p&gt;So I tried to find the proper parts to print, but I must be missing something because the screw holes to hold the display cover still don’t line up.
I don’t care to spend more energy on this; it’s a bit weird but tape does the job well enough.&lt;/p&gt;
&lt;p&gt;At least I got the display cover in an accent color.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Improved-seal-in-extrusions&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Improved-seal-in-extrusions&quot; class=&quot;heading-ref&quot;&gt;Improved seal in extrusions&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/trident/sugru.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Despite having the Nevermore filter and a HEPA filter exhaust, I could very clearly smell ABS fumes from the printer.
Looking at the extrusions, there were large holes in the blind joints and I suspect that doesn’t help.&lt;/p&gt;
&lt;p&gt;Therefore I tried to cover up the holes with some Sugru.
It’s better, but I should probably replace the front door too.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Are-we-done-yet&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Are-we-done-yet&quot; class=&quot;heading-ref&quot;&gt;Are we done yet?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s true that the printer can now be considered Done™—and it has been done for a while—but I still have some mods I’d like to document before I wrap up this build series.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Exploring the Gleam FFI</title><id>http://jonashietala.se/blog/2024/01/11/exploring_the_gleam_ffi/index.html</id><updated>2025-08-11T06:08:20+00:00</updated><link href="https://www.jonashietala.se/blog/2024/01/11/exploring_the_gleam_ffi" rel="alternate"/><published>2024-01-11T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;My brain is a curious thing.
I’m on a business trip right now and I’ve set aside time to finish some important todos I want and need to get done.
But instead of focusing on them, I started playing around with &lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam&lt;/a&gt;—a young and interesting programming language.&lt;/p&gt;
&lt;p&gt;My (current) favorite programming languages are &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt;.
They’re really different from each other, but they work well together as Rust can easily be &lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;embedded via Erlang NIFs&lt;/a&gt;.
This is useful because one of the drawbacks with Elixir (or rather the Erlang VM that Elixir runs on) is raw computational performance,
something that Rust excels at.&lt;/p&gt;
&lt;p&gt;Another drawback with Elixir is the lack of typing (although &lt;a href=&quot;https://nitter.net/josevalim/status/1744395345872683471&quot;&gt;improvements are underway&lt;/a&gt;).
This is what drew me to Gleam, which feels like Elixir but with Rust types on top—a fantastic sales pitch.&lt;/p&gt;
&lt;p&gt;A big drawback with young languages is that there aren’t a lot of libraries out there, so you’ll have to roll your own solutions most of the time.
But the beauty of targeting existing platforms is that you can also leverage their libraries,
which in Gleam’s case means all Erlang and Elixir libraries (or JavaScript, depending on your compilation target).
This is accomplished via Gleam’s FFI, which is quite convenient.&lt;/p&gt;
&lt;p&gt;Let’s explore.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Prerequisites&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Prerequisites&quot; class=&quot;heading-ref&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to follow along, make sure you have the respective compilers installed.
I’ll base the examples from a clean new repo:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; new myapp
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Erlang&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Erlang&quot; class=&quot;heading-ref&quot;&gt;Erlang&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As shown in &lt;a href=&quot;https://gleam.run/book/tour/external-functions.html&quot;&gt;the Gleam Book&lt;/a&gt; calling standard Erlang functions is straightforward.
You declare foreign functions with the &lt;code&gt;@external&lt;/code&gt; keyword and then call them as normal:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;gleam/io&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;erlang&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;rand&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;uniform&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;random_float&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;Float&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;random_float&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That if run will call the &lt;code&gt;uniform&lt;/code&gt; function in the &lt;code&gt;rand&lt;/code&gt; Erlang module:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;0.43487935467166317
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works for standard libraries, but you can access other Erlang libraries on &lt;a href=&quot;https://hex.pm/&quot;&gt;Hex&lt;/a&gt; by adding them as dependencies in &lt;code&gt;gleam.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;base32&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;~&amp;gt; 0.1.0&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Declare and call it like before:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;erlang&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;base32&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;encode&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;encode_base32&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;String&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;encode_base32&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;superhidden&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And Gleam will download and compile the Erlang dependency:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Compiling base32
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Fetching rebar3_hex v7.0.7
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Fetching hex_core v0.8.4
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Fetching verl v1.1.1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Analyzing applications...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Compiling hex_core
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Compiling verl
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Compiling rebar3_hex
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Analyzing applications...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;===&amp;gt; Compiling base32
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&amp;quot;ON2XAZLSNBUWIZDFNY======&amp;quot;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to write Erlang code yourself and call that, it’s also very easy.
The gleam compiler will compile and include &lt;code&gt;.erl&lt;/code&gt; files automatically.&lt;/p&gt;
&lt;p&gt;For example this file &lt;code&gt;src/erlib.erl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;erlang&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight erlang&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor namespace erlang&quot;&gt;&lt;span class=&quot;punctuation definition keyword erlang&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;keyword control directive namespace erlang&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;meta preprocessor namespace arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor namespace arguments erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;entity name namespace erlang&quot;&gt;erlib&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor namespace erlang&quot;&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor export erlang&quot;&gt;&lt;span class=&quot;punctuation definition keyword erlang&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;keyword control directive export erlang&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;meta preprocessor export arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor export arguments erlang&quot;&gt;&lt;span class=&quot;meta sequence list erlang&quot;&gt;&lt;span class=&quot;punctuation section sequence begin erlang&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta reference function name erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable function erlang&quot;&gt;ping&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function erlang&quot;&gt;&lt;span class=&quot;punctuation separator reference erlang&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function arity erlang&quot;&gt;&lt;span class=&quot;meta number integer decimal erlang&quot;&gt;&lt;span class=&quot;constant numeric value erlang&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end erlang&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor export erlang&quot;&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;entity name function erlang&quot;&gt;ping&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function erlang&quot;&gt; &lt;span class=&quot;punctuation separator clause-head-body erlang&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable namespace erlang&quot;&gt;io&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation accessor double-colon erlang&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta function-call identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable function erlang&quot;&gt;fwrite&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double erlang&quot;&gt;&lt;span class=&quot;punctuation definition string begin erlang&quot;&gt;&amp;quot;&lt;/span&gt;ping&lt;span class=&quot;constant other placeholder erlang&quot;&gt;&lt;span class=&quot;punctuation definition placeholder erlang&quot;&gt;~&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant other placeholder control character erlang&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end erlang&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments erlang&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence list erlang&quot;&gt;&lt;span class=&quot;punctuation section sequence begin erlang&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end erlang&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Declare and call the function in gleam like before:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;erlang&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;erlib&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;ping&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; a
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ping
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also call Gleam functions from Erlang.
With for example this pong function in &lt;code&gt;src/mypong.gleam&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;gleam/io&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;pong&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;pong&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can call the Gleam function with &lt;code&gt;module:function()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;erlang&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight erlang&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;entity name function erlang&quot;&gt;ping&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function erlang&quot;&gt; &lt;span class=&quot;punctuation separator clause-head-body erlang&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable namespace erlang&quot;&gt;io&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation accessor double-colon erlang&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta function-call identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable function erlang&quot;&gt;fwrite&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double erlang&quot;&gt;&lt;span class=&quot;punctuation definition string begin erlang&quot;&gt;&amp;quot;&lt;/span&gt;ping from Erlang&lt;span class=&quot;constant other placeholder erlang&quot;&gt;&lt;span class=&quot;punctuation definition placeholder erlang&quot;&gt;~&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant other placeholder control character erlang&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end erlang&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments erlang&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta sequence list erlang&quot;&gt;&lt;span class=&quot;punctuation section sequence begin erlang&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end erlang&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator expressions erlang&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable namespace erlang&quot;&gt;mypong&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation accessor double-colon erlang&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta function-call identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable function erlang&quot;&gt;pong&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;comment line percentage erlang&quot;&gt;&lt;span class=&quot;punctuation definition comment erlang&quot;&gt;%&lt;/span&gt; Call the Gleam function
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ping from Erlang
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pong
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Elixir&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Elixir&quot; class=&quot;heading-ref&quot;&gt;Elixir&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to include Gleam code into an existing Elixir project, look at &lt;a href=&quot;https://github.com/gleam-lang/mix_gleam&quot;&gt;MixGleam&lt;/a&gt; on how to teach &lt;code&gt;mix&lt;/code&gt; how to work with Gleam code and dependencies.
But if you want to include Elixir code into your Gleam project, you can do that just as easily as with Erlang.&lt;/p&gt;
&lt;p&gt;Declaring foreign Elixir functions uses the same &lt;code&gt;@external&lt;/code&gt; keyword:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;gleam/io&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;erlang&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Elixir.RandomColor&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;hex&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;random_color&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;String&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;random_color&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that Elixir modules gets an &lt;code&gt;Elixir&lt;/code&gt; prefix and that we’re still calling external Erlang code as Elixir gets compiled to Erlang.&lt;/p&gt;
&lt;p&gt;Dependencies are added from &lt;a href=&quot;https://hex.pm/&quot;&gt;Hex&lt;/a&gt;, exactly the same as with Erlang dependencies:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; add random_color
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;#3724C9
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Calling our own Elixir code is just as easy as with Erlang.
Just include it in your source directory, like this &lt;code&gt;src/exlib.ex&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;elixir&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight elixir&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta module elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;entity name class elixir&quot;&gt;Exlib&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;  &lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;entity name class elixir&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;puts&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string elixir&quot;&gt;&lt;span class=&quot;string quoted double elixir&quot;&gt;&lt;span class=&quot;punctuation definition string begin elixir&quot;&gt;&amp;quot;&lt;/span&gt;ping from Elixir&lt;span class=&quot;punctuation definition string end elixir&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other symbol elixir&quot;&gt;&lt;span class=&quot;punctuation definition constant elixir&quot;&gt;:&lt;/span&gt;mypong&lt;/span&gt;&lt;span class=&quot;punctuation separator method elixir&quot;&gt;.&lt;/span&gt;pong&lt;span class=&quot;punctuation section function elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And refer to the module as &lt;code&gt;Elixir.Exlib&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;erlang&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;Elixir.Exlib&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;ping&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; a
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ping from Elixir
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pong
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Keep in mind that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You can’t directly call Elixir macros (they happen on compile time).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you include Elixir you’ll also include the Elixir standard library.&lt;/p&gt;
&lt;p&gt;Erlang might be a better choice if you want something more lightweight.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Rust&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Rust&quot; class=&quot;heading-ref&quot;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the beginning I wrote that you could easily call Rust code from Elixir via &lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;rustler&lt;/a&gt;.
You can call Rust from Gleam as well, either via Erlang or Elixir.
&lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;Rustler&lt;/a&gt; recommends to use &lt;code&gt;mix&lt;/code&gt; with Elixir, but we can do this with Erlang and keep using the Gleam toolchain.&lt;/p&gt;
&lt;p&gt;First we need to create a Rust project somewhere.
We can create it in the top level of the Gleam repo or in a &lt;code&gt;native/&lt;/code&gt; folder or wherever.
For this example I’ll just leave it at the top:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;cargo&lt;/span&gt; new rslib --lib
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On the Rust side I’ll use &lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;rustler&lt;/a&gt; to create the NIF:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;cd&lt;/span&gt; rslib/
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;cargo&lt;/span&gt; add rustler
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And in &lt;code&gt;rslib/src/lib.rs&lt;/code&gt; we’ll tag the function we want to expose with &lt;a href=&quot;https://github.com/rusterlium/rustler&quot;&gt;rustler&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;rustler&lt;/span&gt;::&lt;span class=&quot;variable annotation rust&quot;&gt;nif&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;truly_random&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;i64&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Chosen by fair dice roll. Guaranteed to be random.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta path rust&quot;&gt;rustler&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;init&lt;span class=&quot;keyword operator rust&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;librs&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;truly_random&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We want to build this as a dynamic library, so we’ll need to update &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;toml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight toml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;property&quot;&gt;crate-type&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;dylib&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then build it in release mode:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;cargo&lt;/span&gt; build --release
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  ...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should generate the library at &lt;code&gt;target/release/librslib.so&lt;/code&gt;.
Yes, my naming choice here sucked, but let’s roll with it.&lt;/p&gt;
&lt;p&gt;For Gleam to be able to use this file we need to copy it to &lt;code&gt;priv/&lt;/code&gt; (relative to the Gleam root, not the Rust project):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;mkdir&lt;/span&gt; ../priv
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;cp&lt;/span&gt; target/release/librslib.so ../priv/
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The file layout should look something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;├── README.md
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── build
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── gleam.toml
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── manifest.toml
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── priv
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   └── librslib.so     # The important part
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;├── rslib
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── Cargo.lock
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── Cargo.toml
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   ├── src
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   │   └── lib.rs
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;│   └── target
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;└── src
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    └── myapp.gleam
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;update&quot;&gt;
&lt;div class=&quot;info&quot;&gt;Update &lt;span class=&quot;date&quot;&gt;2024-08-30&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;I only tested this on Linux where the &lt;code&gt;.so&lt;/code&gt; extension is used but I didn’t test it on Mac or Windows.&lt;/p&gt;
&lt;p&gt;I’m told that on Mac a &lt;code&gt;.dylib&lt;/code&gt; file will be generated but you should still copy it to the &lt;code&gt;priv/&lt;/code&gt; folder with the &lt;code&gt;.so&lt;/code&gt; extension:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;cp&lt;/span&gt; target/release/librslib.dylib ../priv/librslib.so
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On Windows a &lt;code&gt;.dll&lt;/code&gt; file will be generated and that’s also the extension that should be used in the &lt;code&gt;priv/&lt;/code&gt; folder.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;To include the library we’ll use some Erlang.
We’ll use &lt;code&gt;src/rslib.erl&lt;/code&gt; similar to before, but with &lt;a href=&quot;https://www.erlang.org/doc/tutorial/nif.html&quot;&gt;Erlang NIFs&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;erlang&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight erlang&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor namespace erlang&quot;&gt;&lt;span class=&quot;punctuation definition keyword erlang&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;keyword control directive namespace erlang&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;meta preprocessor namespace arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor namespace arguments erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;entity name namespace erlang&quot;&gt;librs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor namespace erlang&quot;&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor export erlang&quot;&gt;&lt;span class=&quot;punctuation definition keyword erlang&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;keyword control directive export erlang&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;meta preprocessor export arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor export arguments erlang&quot;&gt;&lt;span class=&quot;meta sequence list erlang&quot;&gt;&lt;span class=&quot;punctuation section sequence begin erlang&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta reference function name erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable function erlang&quot;&gt;truly_random&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function erlang&quot;&gt;&lt;span class=&quot;punctuation separator reference erlang&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function arity erlang&quot;&gt;&lt;span class=&quot;meta number integer decimal erlang&quot;&gt;&lt;span class=&quot;constant numeric value erlang&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end erlang&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor export erlang&quot;&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor attribute erlang&quot;&gt;&lt;span class=&quot;punctuation definition keyword erlang&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;keyword control directive attribute erlang&quot;&gt;nifs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor attribute arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor attribute arguments erlang&quot;&gt;&lt;span class=&quot;meta sequence list erlang&quot;&gt;&lt;span class=&quot;punctuation section sequence begin erlang&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta reference function name erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable function erlang&quot;&gt;truly_random&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function erlang&quot;&gt;&lt;span class=&quot;punctuation separator reference erlang&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function arity erlang&quot;&gt;&lt;span class=&quot;meta number integer decimal erlang&quot;&gt;&lt;span class=&quot;constant numeric value erlang&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section sequence end erlang&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor attribute erlang&quot;&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor attribute erlang&quot;&gt;&lt;span class=&quot;punctuation definition keyword erlang&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;keyword control directive attribute erlang&quot;&gt;on_load&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor attribute arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor attribute arguments erlang&quot;&gt;&lt;span class=&quot;meta reference function name erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;variable function erlang&quot;&gt;init&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function erlang&quot;&gt;&lt;span class=&quot;punctuation separator reference erlang&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta reference function arity erlang&quot;&gt;&lt;span class=&quot;meta number integer decimal erlang&quot;&gt;&lt;span class=&quot;constant numeric value erlang&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor attribute erlang&quot;&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;entity name function erlang&quot;&gt;init&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function erlang&quot;&gt; &lt;span class=&quot;punctuation separator clause-head-body erlang&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant language exception type erlang&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;keyword operator assignment erlang&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;support namespace erlang&quot;&gt;erlang&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation accessor double-colon erlang&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path erlang&quot;&gt;&lt;span class=&quot;meta function-call identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;support function erlang&quot;&gt;load_nif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double erlang&quot;&gt;&lt;span class=&quot;punctuation definition string begin erlang&quot;&gt;&amp;quot;&lt;/span&gt;priv/librslib&lt;span class=&quot;punctuation definition string end erlang&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments erlang&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal erlang&quot;&gt;&lt;span class=&quot;constant numeric value erlang&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;entity name function erlang&quot;&gt;truly_random&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters begin erlang&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters erlang&quot;&gt;&lt;span class=&quot;punctuation section parameters end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function erlang&quot;&gt; &lt;span class=&quot;punctuation separator clause-head-body erlang&quot;&gt;-&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call identifier erlang&quot;&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;support function erlang&quot;&gt;exit&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments erlang&quot;&gt;&lt;span class=&quot;punctuation section arguments begin erlang&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta atom erlang&quot;&gt;&lt;span class=&quot;constant other symbol erlang&quot;&gt;nif_library_not_loaded&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end erlang&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator clause erlang&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We now load the &lt;code&gt;librslib&lt;/code&gt; library, declare &lt;code&gt;truly_random&lt;/code&gt; as a NIF with &lt;code&gt;-nifs(..)&lt;/code&gt; and add a function placeholder that will be replaced when the library loads.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;Please note that we need to use the same name &lt;code&gt;librs&lt;/code&gt; in both the Erlang module and in &lt;code&gt;rustler::init!&lt;/code&gt;, otherwise &lt;code&gt;init()&lt;/code&gt; will silently fail and you’ll get an &lt;code&gt;undefined function&lt;/code&gt; error.
To tease out the error we can skip &lt;code&gt;on_load&lt;/code&gt; and call &lt;code&gt;init()&lt;/code&gt; manually from Gleam.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;With the Erlang code in place what’s left is to call the Erlang function from Gleam:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;module&quot;&gt;gleam/io&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;erlang&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;librs&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;truly_random&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;truly_random&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;String&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;truly_random&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we can call our &lt;a href=&quot;https://xkcd.com/221/&quot;&gt;truly random&lt;/a&gt; Rust function!&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;4
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While Rust is amazing, and it’s great that we can call it from Gleam, there are some drawbacks to be aware of:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The glue is verbose as we need to duplicate the function name a bunch of times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Building the library and moving it to &lt;code&gt;priv/&lt;/code&gt; isn’t handled by the Gleam toolchain.
I’ve seen some people use a Makefile to build the library and then copy it to &lt;code&gt;priv/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;NIFs can crash the whole runtime.
While Rust is safer than C, it can still bring the whole runtime down and not just a single Erlang process.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Calling Gleam code from Rust seems harder.
I found an example of &lt;a href=&quot;https://github.com/Qqwy/elixir-rustler_elixir_fun&quot;&gt;calling Elixir or Erlang function from Rust&lt;/a&gt;, but I haven’t looked at in more detail.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;JavaScript&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#JavaScript&quot; class=&quot;heading-ref&quot;&gt;JavaScript&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Gleam can also compile to JavaScript, and this blog post wouldn’t be complete without a short example.&lt;/p&gt;
&lt;p&gt;To compile for JavaScript we can add &lt;code&gt;target = javascript&lt;/code&gt; to our &lt;code&gt;gleam.toml&lt;/code&gt; or use the target flag:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run --target javascript
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Like before when we called Erlang and Elixir files, if you add a JavaScript source file in &lt;code&gt;src/&lt;/code&gt; it will automatically get included.
For example this &lt;code&gt;src/jslib.mjs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;js&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight js&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword import js&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic js&quot;&gt;*&lt;/span&gt; as gleam from &lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;./mypong.mjs&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator statement js&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta export js&quot;&gt;&lt;span class=&quot;keyword control import-export js&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;meta function js&quot;&gt;&lt;span class=&quot;keyword declaration function js&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function js&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;meta function parameters js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function parameters js&quot;&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function js&quot;&gt; &lt;span class=&quot;meta block js&quot;&gt;&lt;span class=&quot;punctuation section block begin js&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  console&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;log&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;meta string js&quot;&gt;&lt;span class=&quot;string quoted double js&quot;&gt;&lt;span class=&quot;punctuation definition string begin js&quot;&gt;&amp;quot;&lt;/span&gt;ping from JavaScript&lt;span class=&quot;punctuation definition string end js&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator statement js&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  gleam&lt;span class=&quot;punctuation accessor js&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;variable function js&quot;&gt;pong&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call js&quot;&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group begin js&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments js&quot;&gt;&lt;span class=&quot;meta group js&quot;&gt;&lt;span class=&quot;punctuation section group end js&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator statement js&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end js&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And to declare the foreign function, we now use the relative file instead of the library name:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;gleam&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight gleam&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable&quot;&gt;javascript&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;./jslib.mjs&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;ping&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation delimiter&quot;&gt;-&amp;gt;&lt;/span&gt; a
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation bracket&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable&quot;&gt;ping&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation bracket&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And when run you’ll see that we can call the JavaScript &lt;code&gt;ping&lt;/code&gt; function which in turns calls our Gleam &lt;code&gt;pong&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish-shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation special&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;function&quot;&gt;gleam&lt;/span&gt; run --target javascript
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ping from JavaScript
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pong
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can inspect the output JavaScript files in &lt;code&gt;build/dev/javascript/myapp/&lt;/code&gt;, which is very useful when debugging or trying to understand the code Gleam generates.&lt;/p&gt;
&lt;aside class=&quot;note&quot;&gt;
&lt;p&gt;I use the NodeJS runtime out of pure lazyness, and then you have to use the &lt;code&gt;.mjs&lt;/code&gt; file extension.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;section id=&quot;Ending-thoughts&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Ending-thoughts&quot; class=&quot;heading-ref&quot;&gt;Ending thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hope this post gives helps you understand how to get started with Gleam’s FFI system.
I haven’t looked into Gleam more than a few days, but given how easy it is to get access to my other favorite languages and their ecosystems, I don’t have to worry that I’ll be missing out on some crucial functionality if I’m going to create something real with Gleam.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>2023 in review</title><id>http://jonashietala.se/blog/2024/01/01/2023_in_review/index.html</id><updated>2024-12-16T08:52:47+00:00</updated><link href="https://www.jonashietala.se/blog/2024/01/01/2023_in_review" rel="alternate"/><published>2024-01-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is my &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly reviews&quot;&gt;yearly review&lt;/a&gt; #14.
Amazing that I’ve kept up with this for 14 years.&lt;/p&gt;
&lt;p&gt;Even though it’s not anything advanced, I really like looking back at the year to see what has happened.
Maybe it’s a very light version of a &lt;a href=&quot;https://www.inc.com/jessica-stillman/happiness-fulfillment-reverse-bucket-list.html&quot; title=&quot;The Secret to Happiness, According to This Harvard Professor: A Reverse Bucket List&quot;&gt;reverse bucket list&lt;/a&gt;, and I can see that it provides some of the same happiness benefits.&lt;/p&gt;
&lt;h1&gt;2023 Non-Geek Achievements&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All my three kids are happy and healthy.&lt;/p&gt;
&lt;p&gt;It’s thanks to Veronica, but I’d like to think I’ve contributed something.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote &lt;a href=&quot;/blog/2023/&quot; title=&quot;My blog posts in 2023&quot;&gt;17 blog posts&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Most of them were written (and published) in the last quarter where I got bitten by the blogging bug.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2023 Geek Achievements&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2023/06/16/i_beat_ftl_on_hard_with_all_ships_in_the_game/&quot; title=&quot;I beat FTL on Hard with all ships in the game&quot;&gt;I beat FTL on Hard with all ships in the game&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/series/voron_trident/&quot; title=&quot;Series: Let&amp;#39;s build a VORON Trident&quot;&gt;I built a VORON&lt;/a&gt; and got into 3D printing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=37995254&quot;&gt;Two&lt;/a&gt; of my &lt;a href=&quot;https://news.ycombinator.com/item?id=38112596&quot;&gt;blog&lt;/a&gt; posts got to the front page of Hacker News.&lt;/p&gt;
&lt;p&gt;I’ve always blogged to write for myself and never because I wanted my blog to be popular, but it was still nice to see some people appreciate it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I &lt;a href=&quot;/blog/2023/10/01/rewriting_my_neovim_config_in_lua/&quot; title=&quot;Rewriting my Neovim config in Lua&quot;&gt;rewrote my Neovim config in Lua&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I gave the blog a &lt;a href=&quot;/blog/2023/10/04/giving_the_blog_a_facelift/&quot; title=&quot;Giving the blog a facelift&quot;&gt;sorely needed facelift&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I wrapped up my series about the &lt;a href=&quot;/series/t-34/&quot; title=&quot;The T-34 keyboard layout&quot;&gt;T-34 keyboard layout&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2023 Misadventures&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;While I finished the eBook of &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?: What they are, what they do, and why they matter&quot;&gt;my book&lt;/a&gt;, I only made it available for purchase using cryptocurrencies a short amount of time.&lt;/p&gt;
&lt;p&gt;The reason is that I made it available with &lt;a href=&quot;https://github.com/bitpal/bitpal&quot; title=&quot;BitPal is a self-hosted payment processor&quot;&gt;my payment processor&lt;/a&gt;, but I ran out of energy so I shut down the server.
I really need to get it together and just upload it somewhere so it’s purchasable normally.&lt;/p&gt;
&lt;p&gt;Maybe I should just make it available for free, so I can close the chapter on the book project?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I didn’t read that many books—at least I don’t remember that I did.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Despite me trying to reduce it, the boardgame list of shame grew this year.&lt;/p&gt;
&lt;p&gt;There’s a complete stop to Kickstarters and buying new games until I correct this mess.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Plans for 2024&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Focus on mental and physical health, with a focus on strength training.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally complete the book project by putting the eBook widely available and finishing the &lt;a href=&quot;/series/making-cryptobook/&quot; title=&quot;How I wrote &amp;#39;Why Cryptocurrencies?&amp;#39;&quot;&gt;How I wrote ‘Why Cryptocurrencies?’&lt;/a&gt; series.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finish my planned mods on my &lt;a href=&quot;/series/voron_trident/&quot; title=&quot;Series: Let&amp;#39;s build a VORON Trident&quot;&gt;VORON&lt;/a&gt; 3D printer and complete the blog series.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complete my Git rewrite in Rust project, that i left hanging back in 2020.&lt;/p&gt;
&lt;p&gt;I’m already thinking of postponing this again…
But maybe I can make some amount of progress at least?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start a new long-term project.&lt;/p&gt;
&lt;p&gt;I’ve promised myself to finish up my ongoing projects before I’m allowed to do this, but we’ll see how that goes.
(Not well I suppose.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Filters</title><id>http://jonashietala.se/blog/2023/12/15/lets_build_a_voron_filters/index.html</id><updated>2026-01-29T10:44:48+00:00</updated><link href="https://www.jonashietala.se/blog/2023/12/15/lets_build_a_voron_filters" rel="alternate"/><published>2023-12-15T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I can print, but the printer is missing a very important thing that I alluded to in the previous post: filtering dangerous particles and fumes.&lt;/p&gt;
&lt;p&gt;This is mostly covered by the kit, but I was missing some parts from the &lt;a href=&quot;https://pif.voron.dev/&quot; title=&quot;VORON print it forward&quot;&gt;print it forward&lt;/a&gt; and the kit didn’t include a HEPA filter.
Because the printer is in the office and health is super important fixing this was needed so I could start printing some ABS and continue modding the printer.&lt;/p&gt;
&lt;h1&gt;Exhaust cover&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/exhaust_cover_hole.jpg&quot; /&gt;
&lt;figcaption&gt;I’m missing the exhaust cover where the filter goes in a stock VORON.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The standard VORON comes with a filter in the back, but the LDO kit doesn’t include the fan for the filter and instead uses an &lt;a href=&quot;https://github.com/MotorDynamicsLab/LDOVoron2/blob/main/STLs/exhaust_cover.stl&quot; title=&quot;LDO exhaust cover&quot;&gt;exhaust cover&lt;/a&gt; to close the hole.&lt;/p&gt;
&lt;p&gt;I didn’t receive this part, so the first thing I did was to print that part.
This was just a very temporary measure so I printed it in PLA.&lt;/p&gt;
&lt;h1&gt;Nevermore filter&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/nevermore_installed.jpg&quot; /&gt;
&lt;figcaption&gt;The Nevermore filter is installed next to the back panel.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The LDO kit includes the &lt;a href=&quot;https://github.com/nevermore3d/Nevermore_Micro&quot; title=&quot;Nevermore Micro filter&quot;&gt;Nevermore filter&lt;/a&gt;, which removes VOCs.
I was confused on how to install it as at the time the LDO docs only mentioned how to install it on a 2.4, not on a Trident.
When I brought it up they &lt;a href=&quot;https://www.ldomotion.com/p/guide/Nevermore-V5-Duo--Trident&quot; title=&quot;LDO Nevermore Trident installation&quot;&gt;fixed it &lt;/a&gt; so no big deal.&lt;/p&gt;
&lt;p&gt;But they wanted me to mount it using a plenum mount, which my parts didn’t have.
I think I received an older version of the Nevermore from the &lt;a href=&quot;https://pif.voron.dev/&quot; title=&quot;VORON print it forward&quot;&gt;print it forward&lt;/a&gt; service so I couldn’t use it.&lt;/p&gt;
&lt;p&gt;I instead printed out the updated plenum and frame connector myself.
Because the point of the Nevermore is to be able to print ABS safely I did this in PLA as well.
I know it’s not ideal, but it will have to do.
Lazy as I am I’ll run with this and if it breaks I’ll replace it then.&lt;/p&gt;
&lt;p&gt;I also added some strips of foam tape to the back of the filter to prevent it from scrambling against the back panel.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/nevermore_fans.jpg&quot; /&gt;
&lt;figcaption&gt;Cutting away parts from the fans was horrible. They broke very easily.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/nevermore_solder.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;I finally got to exercise my (very poor) soldering skills!
It was cute how LDO included a small board so that you don’t have to crimp any cables.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;HEPA exhaust filter&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/hepa_filter.jpg&quot; /&gt;
&lt;figcaption&gt;A new HEPA filter. I wasn’t able to color match with the print-it-forward parts…&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;While I have the Nevermore filter, it doesn’t filter Ultra-Fine Particulates.
For that you need a HEPA filter.&lt;/p&gt;
&lt;p&gt;There were a few solutions with combined carbon and HEPA filter, but since I already have the Nevermore I wanted a standalone HEPA filter.
I found the &lt;a href=&quot;https://github.com/jmattingley23/voron-hepa-exhaust-filter&quot;&gt;Voron HEPA Exhaust Filter&lt;/a&gt; that replaces the stock filter that seemed like a good option.&lt;/p&gt;
&lt;p&gt;With the Nevermore in place I could print the parts using ABS, and they turned out pretty well.&lt;/p&gt;
&lt;p&gt;For silence I used a &lt;a href=&quot;https://noctua.at/en/nf-a6x25-flx&quot; title=&quot;Noctua FN-A6x25&quot;&gt;Noctua FN-A6x25&lt;/a&gt; fan.
In hindsight I maybe should’ve used the &lt;a href=&quot;https://www.nicksherlock.com/2022/01/driving-a-4-pin-computer-pwm-fan-on-the-btt-octopus-using-klipper/&quot; title=&quot;Driving a 4-pin computer PWM fan on the BTT Octopus using Klipper&quot;&gt;PWM variant&lt;/a&gt;, if only to make the wiring simpler.
Now I have this ugly looking wiring in the top corner (it uses the Noctua low-noise adapter).&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/hepa_filter_wire.jpg&quot;&gt;&lt;img src=&quot;/images/trident/hepa_filter_wire.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/ugly_wire.jpg&quot;&gt;&lt;img src=&quot;/images/trident/ugly_wire.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I also had to create another cable, which wasn’t &lt;em&gt;too&lt;/em&gt; difficult:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Converted the 3-pin cable to a 2-pin JST connector and extended it.&lt;/p&gt;
&lt;p&gt;I simply ignored &lt;a href=&quot;https://faqs.noctua.at/en/support/solutions/articles/101000081757&quot; title=&quot;What pin configuration do Noctua fans use?&quot;&gt;the yellow RPM speed signal cable&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect to a free fan output on the Octopus.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Used the 12V selection jumper for the fan output.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Klipper setup&lt;/h1&gt;
&lt;p&gt;With the fans installed you also need to configure Klipper to utilize them.&lt;/p&gt;
&lt;p&gt;I setup them both as generic fans, so I can control them from the start and end macros:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[fan_generic nevermore_fan]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;##  Nevermore fan - FAN3
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pin: PD13
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;max_power: 1.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;kick_start_time: 5.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[fan_generic filter_fan]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;##  HEPA filter fan - FAN4
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pin: PD14
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;max_power: 1.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;kick_start_time: 5.0
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then in &lt;code&gt;PRINT_START&lt;/code&gt; I turn on the fans:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;SET_FAN_SPEED FAN=nevermore_fan SPEED=1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;SET_FAN_SPEED FAN=filter_fan SPEED=1
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After the print has finished I don’t want to just turn off the fans immediately, but have them run a bit after the print has finished to clear out any toxic fumes.
I accomplished this with a &lt;code&gt;delayed_gcode&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[delayed_gcode _VENT_OFF]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Venting done&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_FAN_SPEED FAN=nevermore_fan SPEED=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_FAN_SPEED FAN=filter_fan SPEED=0
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That I call in &lt;code&gt;PRINT_END&lt;/code&gt; with a timeout:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;# Turn off fans after 30 min
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;UPDATE_DELAYED_GCODE ID=_VENT_OFF DURATION=1800
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To prevent the fans from turning off mid-print if I get impatient and start a new print before &lt;code&gt;_VENT_OFF&lt;/code&gt; has been called I also clear the delayed gcode in &lt;code&gt;PRINT_START&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;# Prevent Nevermore and filter fan from being turned off mid print
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;UPDATE_DELAYED_GCODE ID=_VENT_OFF DURATION=0
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now the filter fans turn on and off automatically.&lt;/p&gt;
&lt;p&gt;Some people run the Nevermore on 50–80% during print and then go 100% at the end, but I don’t know why you can’t run it at 100% all the time so that’s what I do.&lt;/p&gt;
&lt;h2&gt;Reworked &lt;code&gt;PRINT_START&lt;/code&gt;/&lt;code&gt;PRINT_END&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I also rewrote the &lt;code&gt;PRINT_START&lt;/code&gt; and &lt;code&gt;PRINT_END&lt;/code&gt; macros to make a little more sense to me.
Here they are in their entirety:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[gcode_macro PRINT_START]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Fetch data from slicer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {% set target_bed = params.BED|int %}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {% set target_extruder = params.EXTRUDER|int %}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {% set target_chamber = params.CHAMBER|default(0)|int %}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Set temps for bed and extruder without waiting to save some time
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Preheating&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={target_bed}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_HEATER_TEMPERATURE HEATER=extruder TARGET=150
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Homing&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G28                                                     # Full home (XYZ)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G90                                                     # Absolute position
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G92 E0                                                  # Reset extruder
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  BED_MESH_CLEAR                                          # Clears old saved bed mesh (if any)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  CLEAR_PAUSE                                             # Ensure that we can&apos;t accidentally resume an old pause
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Prevent Nevermore and filter fan from being turned off mid print
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  UPDATE_DELAYED_GCODE ID=_VENT_OFF DURATION=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Bed: {target_bed}c&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # We&apos;re in the center of the bed after full home
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  M190 S{target_bed}                                      # Sets the target temp for the bed
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Heating nozzle to 150 degrees. This helps with getting a correct Z-home
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Hotend: 150c&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  M109 S150                                               # Heats the nozzle to 150c
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Turn on fans to help with chamber heating
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_FAN_SPEED FAN=nevermore_fan SPEED=1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  M106 S255                                               # Turns on the PT-fan
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Waits for chamber to reach desired temp
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Heatsoak: {target_chamber}c&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  TEMPERATURE_WAIT SENSOR=&quot;temperature_sensor chamber_temp&quot; MINIMUM={target_chamber}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Only turn on filter after chamber has been heated
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_FAN_SPEED FAN=filter_fan SPEED=1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Z-tilt adjust&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Z_TILT_ADJUST                                           # Levels the buildplate via z_tilt_adjust
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G28 Z                                                   # Homes Z again after z_tilt_adjust
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Bed mesh&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  BED_MESH_CALIBRATE                                      # Starts bed mesh
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Heats up the nozzle up to target via data from slicer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Hotend: {target_extruder}c&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SMART_PARK                                              # KAMP parking routine
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  M107                                                    # Turns off partcooling fan
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  M109 S{target_extruder}                                 # Heats the nozzle to printing temp
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Purge&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  VORON_PURGE                                             # KAMP purge
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G92 E0                                                  # Reset extruder
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Printer goes brr&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[gcode_macro PRINT_END]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # safe anti-stringing move coords
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {% set th = printer.toolhead %}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {% set x_safe = th.position.x + 20 * (1 if th.axis_maximum.x - th.position.x &gt; 20 else -1) %}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {% set y_safe = th.position.y + 20 * (1 if th.axis_maximum.y - th.position.y &gt; 20 else -1) %}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {% set z_safe = [th.position.z + 2, th.axis_maximum.z]|min %}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SAVE_GCODE_STATE NAME=STATE_PRINT_END
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Print done&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  M400                                                        # Wait for buffer to clear
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G92 E0                                                      # Zero the extruder
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G1 E-2.0 F3600                                              # Retract filament
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  TURN_OFF_HEATERS
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G90                                                         # Absolute positioning
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G0 X{x_safe} Y{y_safe} Z{z_safe} F20000                     # Move nozzle to remove stringing
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  G0 X{th.axis_maximum.x//2} Y{th.axis_maximum.y - 2} F3600   # Park nozzle at rear
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  M107                                                        # Turn off partcooling fan
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  # Turn off fans after 30 min
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  UPDATE_DELAYED_GCODE ID=_VENT_OFF DURATION=1800
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  BED_MESH_CLEAR
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  RESTORE_GCODE_STATE NAME=STATE_PRINT_END
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;[delayed_gcode _VENT_OFF]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;gcode:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_DISPLAY_TEXT MSG=&quot;Venting done&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_FAN_SPEED FAN=nevermore_fan SPEED=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  SET_FAN_SPEED FAN=filter_fan SPEED=0
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>Let&apos;s build a VORON: Printing &amp; Tuning</title><id>http://jonashietala.se/blog/2023/11/30/lets_build_a_voron_printing_tuning/index.html</id><updated>2026-01-29T10:45:48+00:00</updated><link href="https://www.jonashietala.se/blog/2023/11/30/lets_build_a_voron_printing_tuning" rel="alternate"/><published>2023-11-30T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s up and running, and now it’s finally printing time!
Less exciting—but necessary—tuning the printer to make the prints better.&lt;/p&gt;
&lt;h1&gt;Filament shipment&lt;/h1&gt;
&lt;p&gt;Even though I’ve been building the printer for more than a month, I wasn’t ready for it being time for printing so soon.
I don’t know what filament is good and what I need, so I decided to get a few different brands and colors to try out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.3djake.com/3djake/niceabs-black?sai=3802&quot;&gt;3DJAKE niceABS Black&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.3djake.com/esun/abs-purple-2?sai=11812&quot;&gt;eSUN ABS+ Purple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Polymaker PolyTerra PLA &lt;a href=&quot;https://www.3djake.com/polymaker/polyterra-pla-army-dark-green?sai=11933&quot;&gt;Army Dark Green&lt;/a&gt; and &lt;a href=&quot;https://www.3djake.com/polymaker/polyterra-pla-army-blue?sai=14897&quot;&gt;Army Blue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.3djake.com/3djake/ecopla-white-black-economy-set?sai=5063&quot;&gt;3DJAKE ecoPLA White &amp;amp; Black&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.3djake.com/spectrum/pla-dragon-red?sai=3969&quot;&gt;Spectrum PLA Dragon Red&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.3djake.com/esun/esilk-pla-gold?sai=11857&quot;&gt;eSUN eSilk PLA Gold&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/filament.jpg&quot; /&gt;
&lt;figcaption&gt;I think I went overboard with the filament order.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;aside&gt;In hindsight I should’ve waited longer to see what materials I wanted to print, now I kind of regret buying so much PLA.&lt;/aside&gt;
&lt;h1&gt;Secondary printer tuning&lt;/h1&gt;
&lt;p&gt;At this point the next step in the VORON docs is &lt;a href=&quot;https://docs.vorondesign.com/build/slicer/first_print.html&quot;&gt;making a print&lt;/a&gt;.
But I had various issues, so I went through the &lt;a href=&quot;https://docs.vorondesign.com/tuning/secondary_printer_tuning.html&quot;&gt;Secondary printer tuning&lt;/a&gt; before getting my first successful print.&lt;/p&gt;
&lt;h2&gt;Gantry racking &amp;amp; squaring&lt;/h2&gt;
&lt;p&gt;I’ve already done the gantry racking, yay!&lt;/p&gt;
&lt;h2&gt;Belt tension&lt;/h2&gt;
&lt;p&gt;I always wondered how tight the belts were supposed to be.
Tuning it by measuring the frequency using an app was pretty nifty, and it was quite painless.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/belt_frequencies.png&quot; /&gt;
&lt;figcaption&gt;It’s around 110Hz, I think?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I tried to tune it to 110Hz, but I’ve seen people aiming for 120Hz.&lt;/p&gt;
&lt;h2&gt;Bed mesh&lt;/h2&gt;
&lt;p&gt;To setup a bed mesh you just add something like this to Klipper:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[bed_mesh]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;speed: 300
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;mesh_min: 40, 40
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;mesh_max: 210, 210
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;fade_start: 0.6
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;fade_end: 10.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;probe_count: 5,5
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;algorithm: bicubic
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then &lt;code&gt;BED_MESH_CALIBRATE&lt;/code&gt; will do it’s job:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/bed_mesh.png&quot; /&gt;
&lt;figcaption&gt;The bed mesh is situated around 0, nothing unexpected here.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I also setup &lt;a href=&quot;https://github.com/kyleisah/Klipper-Adaptive-Meshing-Purging&quot;&gt;Klipper Adaptive Meshing &amp;amp; Purging&lt;/a&gt; (KAMP) using their setup instructions to dynamically adjust the bed to fit the print size.&lt;/p&gt;
&lt;h2&gt;Input shaping&lt;/h2&gt;
&lt;p&gt;The guide references input shaping, which is included in the LDO kit.
&lt;a href=&quot;https://www.youtube.com/@Nero3D&quot;&gt;NERO 3D&lt;/a&gt; recommended to wait with input shaping until you’ve printed with it a bit, so I did the input shaping after ~5 hours of printing time.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/input_shaping.jpg&quot; /&gt;
&lt;figcaption&gt;Input shaping connected.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I didn’t do anything special and just accepted whatever it spat out.&lt;/p&gt;
&lt;h1&gt;First print&lt;/h1&gt;
&lt;p&gt;The VORON docs &lt;a href=&quot;https://docs.vorondesign.com/build/slicer/first_print.html&quot;&gt;makes the first print seem so simple&lt;/a&gt;—just upload the print and eat a bowl of cereal.
And I was looking forward to just hitting print and watching it go brr…
But of course things wouldn’t go so smoothly.&lt;/p&gt;
&lt;p&gt;Problems I’ve had include but isn’t limited to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Print stopped with &lt;code&gt;Hotend not enough&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This happens because the Tap G-code reduces the hotend temperature to 150° when probing to not damage the bed, but then the temperature is too low for printing.&lt;/p&gt;
&lt;p&gt;To fix it I had to manually set bed and hotend temperatures after Tap and modifying SuperSlicer to provide these values to the &lt;code&gt;PRINT_START&lt;/code&gt; macro as detailed in &lt;a href=&quot;https://github.com/jontek2/A-better-print_start-macro&quot;&gt;a better &lt;code&gt;PRINT_START&lt;/code&gt; macro&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Filament didn’t load.&lt;/p&gt;
&lt;p&gt;And KlipperScreen complains about &lt;code&gt;FILAMENT_LOAD&lt;/code&gt; not existing. Sigh.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;First layer not sticking to the bed.&lt;/p&gt;
&lt;p&gt;A combination of using the wrong temperature and &lt;code&gt;z_offset&lt;/code&gt; was to blame.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After a few failed attempts, the filament clogs.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/clogged.jpg&quot; /&gt;
&lt;figcaption&gt;The filament clogged somehow, and I had to disassemble the toolhead to fix it.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bunch of “Unknown command” errors in the mainsail log.&lt;/p&gt;
&lt;p&gt;I assume it’s because Klipper wasn’t selected in the “G-code flavor” in SuperSlicer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The print coming loose from the bed after a while.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/fail_print.jpg&quot; /&gt;
&lt;figcaption&gt;Oh FFS.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I struggled with this a fair bit.
I reconfigured &lt;code&gt;z_offset&lt;/code&gt; which seemed to work, but maybe it’s extruding too much filament causing the toolhead to hit the print?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After all that trouble I was running into I was expecting for getting an absolutely shit print…
But it’s actually not &lt;em&gt;that&lt;/em&gt; terrible?&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/first_cube_top.jpg&quot;&gt;&lt;img src=&quot;/images/trident/first_cube_top.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/first_cube_x.jpg&quot;&gt;&lt;img src=&quot;/images/trident/first_cube_x.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;It’s far from perfect, but the lighting is fairly harsh and it looks better in real-life.
My friends have shown many 3D prints that look a lot worse.&lt;/p&gt;
&lt;h1&gt;Functional prints&lt;/h1&gt;
&lt;p&gt;High on adrenaline I set out to do my first functional print: an &lt;a href=&quot;https://github.com/MotorDynamicsLab/LDOVoron2/blob/main/STLs/exhaust_cover.stl&quot;&gt;exhaust cover&lt;/a&gt; for the back of the printer.
I’m going to replace it with a proper filter in the future, but I wanted something to cover the big hole in the back when printing ABS, so I wanted to make a temporary in PLA.&lt;/p&gt;
&lt;p&gt;But it things can’t go that smoothly:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/fail_print_exhaust.jpg&quot; /&gt;
&lt;figcaption&gt;I messed with the z-offset during print, and the result was this mess.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The printer made some extremely unpleasant sounds, and I was scared that the nozzle was grinding against the bed.
I tried to tweak the z-offset during print, but I the sound didn’t stop and I ended up destroying the print.&lt;/p&gt;
&lt;p&gt;The nozzle didn’t hit the bed and it was the stepper motors being super loud… But more on that in a future post.&lt;/p&gt;
&lt;p&gt;When I re-ran the print and stopped messing with it, the printer spat out a functional print:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/print_exhaust.jpg&quot; /&gt;
&lt;figcaption&gt;Surprisingly good quality.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Other things weren’t that good:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/not_great_nevermore_mount.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;A part needed to mount the Nevermore filter to the extrusion.
It’s hard to see in this image, but the top edge is drifting upwards quite a bit.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Simpler models seem to print well, but it struggles with more complex geometry.
While I can probably use this Nevermore mount with some sanding, this level of quality isn’t high enough to for example print parts for a VORON.&lt;/p&gt;
&lt;p&gt;More tuning is needed.&lt;/p&gt;
&lt;h1&gt;More print tuning&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://ellis3dp.com/Print-Tuning-Guide/&quot;&gt;Ellis’ print tuning guide&lt;/a&gt; seems like the go-to guide for tuning your prints.
It contains a &lt;em&gt;lot&lt;/em&gt; of info, so I won’t write about it too much lest we’ll be here all day.
These are the big things I did:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Extruder calibration&lt;/p&gt;
&lt;p&gt;This contains the images on how to measure the extrusion distance I was missing from the VORON docs.
I redid the calibration but with the top panel removed to get a more accurate measure.
Turns out my previous calibration was 10% off. Yikes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;First layer squish&lt;/p&gt;
&lt;p&gt;I wasn’t really sure how to do this, but I think the point is to print one square using one z-offset and then change it a little for the next square to see which produces the best print.
In SuperSlicer I had to enable the “Complete individual objects” setting for it to print one square at a time.&lt;/p&gt;
&lt;p&gt;My previous z-offset using the paper was pretty damn good, but I ended up accepting a &lt;code&gt;-0.01&lt;/code&gt; extra offset (increasing it to &lt;code&gt;-1.050&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pressure advance&lt;/p&gt;
&lt;p&gt;I used the &lt;a href=&quot;https://ellis3dp.com/Print-Tuning-Guide/articles/pressure_linear_advance/pattern_method.html&quot;&gt;pattern method&lt;/a&gt;, although there were &lt;em&gt;so&lt;/em&gt; many settings I was unsure about so I don’t know how well it worked out.&lt;/p&gt;
&lt;p&gt;Still, I got a value of &lt;code&gt;0.04&lt;/code&gt; and for some reason I didn’t have any pressure advance setting previously.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extrusion multiplier&lt;/p&gt;
&lt;p&gt;It was super difficult for me to tune this as I wasn’t sure what to look for.
I ended up choosing &lt;code&gt;0.98&lt;/code&gt;, but it could’ve just as well be &lt;code&gt;1.0&lt;/code&gt;.
Apparently I should do this for every new filament? How bothersome.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are more things in the guide, but they feel like issues you should keep in mind when printing and not something you tune for from the start.
With the massive amount of tuning options both in Klipper and SuperSlicer I’m sure this will be a topic I’ll have to revisit many times.&lt;/p&gt;
&lt;h1&gt;Some more prints&lt;/h1&gt;
&lt;p&gt;I printed out another calibration cube and I hoped to have some good comparison pictures here,
but truthfully the difference was really small.
There were some slight improvements, but not something that shows up well in pictures.&lt;/p&gt;
&lt;p&gt;So here are some other parts I’ve printed:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/printing_abs.jpg&quot; /&gt;
&lt;figcaption&gt;Printer goes brr.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/printed_parts.jpg&quot; /&gt;
&lt;figcaption&gt;Some of the parts for a HEPA filter housing. If you zoom in you can see some stringing and very visible lines.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/printed_parts2.jpg&quot; /&gt;
&lt;figcaption&gt;The print lines are quite visible.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Despite some artifacts I’m happy with these results,
especially since these were new spools of filament that I didn’t do any tuning or drying for (I don’t have a filament dryer yet).
The prints were absolutely good enough for me to start printing a bunch of mods for the printer.&lt;/p&gt;
</content></entry><entry><title>Writing lessons learned after writing a book</title><id>http://jonashietala.se/blog/2023/11/25/writing_lessons_learned_after_writing_a_book/index.html</id><updated>2024-06-27T07:55:43+00:00</updated><link href="https://www.jonashietala.se/blog/2023/11/25/writing_lessons_learned_after_writing_a_book" rel="alternate"/><published>2023-11-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;&lt;blockquote&gt;A good writer isn’t born; a good writer is created&lt;/blockquote&gt;&lt;/div&gt;
&lt;p&gt;It may sound dumb, but one of my reasons for writing a book was to improve my writing ability.
Maybe I could’ve practiced on the blog instead, but putting things on paper gave it some added weight I don’t think I would’ve gotten otherwise.&lt;/p&gt;
&lt;p&gt;Here are some of my most important writing takeaways I’ve gotten from the process of writing a book.
These aren’t original by any means, just things I’ve collected during the process.
Many details are from the excellent book &lt;a href=&quot;https://www.goodreads.com/book/show/53343.On_Writing_Well&quot;&gt;On Writing Well: The Classic Guide to Writing Nonfiction&lt;/a&gt; that I can’t recommend highly enough.&lt;/p&gt;
&lt;h1&gt;Writing is a skill&lt;/h1&gt;
&lt;p&gt;Realize that writing is a skill.
A skill can be improved, but it will take conscious effort.&lt;/p&gt;
&lt;h2&gt;Deliberate practice&lt;/h2&gt;
&lt;p&gt;Like any skill, the best way to improve it is to &lt;em&gt;practice&lt;/em&gt;.
Without practice, everything else is meaningless.&lt;/p&gt;
&lt;p&gt;But it’s not enough to “just write”, you also need to evaluate your progress and try to notice what you’re lacking and where you can improve.&lt;/p&gt;
&lt;p&gt;Be introspective, think about what you’re doing and be your own critic.
This is an extremely valuable skill, which will helpful no matter what area you want to improve in.&lt;/p&gt;
&lt;p&gt;It can be difficult, here are some questions I try to ask myself whenever I write:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does the text flow nicely?&lt;/li&gt;
&lt;li&gt;Where is the red thread?&lt;/li&gt;
&lt;li&gt;Are you making the case succinctly, or is there lots of fluff?&lt;/li&gt;
&lt;li&gt;What is the purpose of this section/chapter/paragraph?&lt;/li&gt;
&lt;li&gt;Can I remove these words?&lt;/li&gt;
&lt;li&gt;Am I repeating myself?&lt;/li&gt;
&lt;li&gt;Can I replace any of these words to make it simpler, more succinct, or more correct?&lt;/li&gt;
&lt;li&gt;Does the text sound good?&lt;/li&gt;
&lt;li&gt;Are the sentences too short? Too long?&lt;/li&gt;
&lt;li&gt;Is there sufficient variation in the text?&lt;/li&gt;
&lt;li&gt;Are you &lt;a href=&quot;https://practicaltypography.com/type-composition.html&quot;&gt;using the character types&lt;/a&gt;; commas, ellipses, hyphens, dashes and brackets?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Remove unnecessary words&lt;/h2&gt;
&lt;p&gt;My biggest takeaway from &lt;a href=&quot;https://www.goodreads.com/book/show/53343.On_Writing_Well&quot;&gt;On Writing Well&lt;/a&gt; is that if you can remove a word or two from a sentence, it’s probably a good idea to do so.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Quite often we use extra words that don’t really add anything of value.&lt;/li&gt;
&lt;li&gt;We often use extra words that don’t add anything of value.&lt;/li&gt;
&lt;li&gt;We often use redundant words.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s not wise to go overboard, but for me it’s been very helpful to keep in mind.
If I’m not strict on myself I’ve found that I’m very good at adding redundant words everywhere.&lt;/p&gt;
&lt;h2&gt;Keep it simple stupid&lt;/h2&gt;
&lt;p&gt;KISS, a common acronym in software development, is also applicable to writing.
Complexity is an alluring mistress, especially for the bright and motivated,
but using simpler words and sentence structures is often the better way.&lt;/p&gt;
&lt;p&gt;This is especially true in non-fiction where you’re trying to explain a technical concept.
By keeping things simpler—often simpler than you’d like—your explanation will be more easily understood by more people.&lt;/p&gt;
&lt;p&gt;The reader will be tasked hard enough to understand the subject matter at hand, throwing complicated jargon at them will only make understanding harder.&lt;/p&gt;
&lt;p&gt;Yes, it’s difficult to explain a hard subject in simple terms.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If I had more time, I would have written a shorter letter&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Attributed to far too many people&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Be sure, and make it personal&lt;/h2&gt;
&lt;p&gt;One common piece of advice I’d like to push back on is to keep the technical writing dry and impersonal.
The advice is to avoid “you”, “I”, and “in my opinion” while hedging your bets with “maybe”, “there’s a chance”, and “occasionally”.&lt;/p&gt;
&lt;p&gt;It’s much more memorable and interesting to expose your personal opinions and to use strong wording.
If you point out every exception to the rule and add dozens of qualifiers to every statement, you will muddy the water so much that the core message will be drowned out.&lt;/p&gt;
&lt;p&gt;Instead, focus to deliver the core message to the best of your abilities.
Make it colorful and deliver it with confidence.
Show your personality; make it interesting, make it funny, and make it memorable.
The reader will thank you for it.&lt;/p&gt;
&lt;h1&gt;Consistency is the most important thing&lt;/h1&gt;
&lt;p&gt;If you’re going to write a larger piece of work like a book, the most important thing to get it done is working on it consistently.&lt;/p&gt;
&lt;p&gt;Anyone can write when motivation runs high, but what separates the wheat from the chaff is if you write when you’re not motivated.
It’s exactly like exercising; the people who gets results are those who go to the gym when they don’t feel like it, or who go out for a run even when it’s raining like mad.&lt;/p&gt;
&lt;p&gt;It’s comforting to think about very successful authors who only write with the help of inspiration, but I think it’s a trap.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/series/43790-a-song-of-ice-and-fire&quot;&gt;A Song of Ice and Fire&lt;/a&gt; is my favorite book series, but I’m sure that if George R. R. Martin had been more focused on writing consistently—instead of waiting for inspiration—we wouldn’t be here still waiting for the next book a decade later, worried that he’ll die before he finishes the series.&lt;/p&gt;
&lt;p&gt;And he’s not alone. &lt;a href=&quot;https://www.goodreads.com/series/43531-gentleman-bastard&quot;&gt;The Gentlemen Bastard&lt;/a&gt; series is just as good, but we’ve been waiting a decade for the next book there too.
Although I haven’t read it yet, &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Kingkiller_Chronicle&quot;&gt;The Kingkiller Chronicle&lt;/a&gt; is another example.&lt;/p&gt;
&lt;p&gt;Do yourself a favor and turn yourself into an author that grinds out results, not one who waits for inspiration to strike.
The trick is, you can “force” inspiration to come by forcing yourself into writer mode.
And the way to do that is by making it a habit.&lt;/p&gt;
&lt;p&gt;What worked for me was to allocate 15–30 minutes of writing every morning (which sometimes became much more).
Even though I only worked on the book a few hours a week, this consistent work—this habit—worked wonders for me.&lt;/p&gt;
&lt;h1&gt;Rewrite, rewrite, rewrite&lt;/h1&gt;
&lt;p&gt;One thing that may hinder the writing process is that the output isn’t great the first time.
Most of the time it’s just bad, but often it plainly sucks.
And that’s hard to handle, because we don’t want it to suck.
We want it to be great!&lt;/p&gt;
&lt;p&gt;I think the key here is to let go.
Allow it to suck, as long as we get &lt;em&gt;something&lt;/em&gt; down to work with.
Then you’ll move forward and allow yourself to get into writer mode where the words will flow.&lt;/p&gt;
&lt;p&gt;It’s only then that the real writing can start: &lt;strong&gt;the rewrite&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I really think that changing, revising, rewriting, and refactoring is the key to writing well.
It’s the rewrite that will allow you to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make the text fluent.&lt;/li&gt;
&lt;li&gt;Make the writing consistent.&lt;/li&gt;
&lt;li&gt;Find and fix errors, both large and small.&lt;/li&gt;
&lt;li&gt;Reduce fluff.&lt;/li&gt;
&lt;li&gt;Ensure that the core message is delivered as clearly and strongly as possible.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In my mind the rewrite is like polishing a gem.
Without it, the gem is not much more than a glittering rock—
you can see the potential, but it’s nothing special.
Yet after the polish it will sparkle and captivate you.&lt;/p&gt;
&lt;p&gt;The rewrite is essential to good writing.&lt;/p&gt;
&lt;h1&gt;Clarity of thought translates into clear writing&lt;/h1&gt;
&lt;blockquote&gt;&lt;p&gt;Clear thinking becomes clear writing; one can’t exist without the other.&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;William Zinsser&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;Writing can be hard sometimes.
You have a plan, you get something down and you try to rewrite and mold it to something good.
But despite doing everything “right”, what you’ve written still sucks.
It’s frustrating.&lt;/p&gt;
&lt;p&gt;When this happens to me, the problem isn’t the writing itself—it’s my thoughts.&lt;/p&gt;
&lt;p&gt;If your thoughts are muddy and unclear, then what you write will also be muddy and unclear.
But if your thoughts are sharp and clear, then the writing will be also be sharp and clear.&lt;/p&gt;
&lt;p&gt;In practice this means it’s often better to take a step back and organize your thoughts than to force unfinished ideas on paper.&lt;/p&gt;
&lt;p&gt;It may sound like it runs counter to my previous advice of getting something down and then working with it, but I think they compliment each other.
Rewriting is one way of organizing your thoughts, but it’s not a panacea.&lt;/p&gt;
&lt;h1&gt;Have a plan and an outline&lt;/h1&gt;
&lt;p&gt;Another way of organizing your thoughts is to approach writing top-down instead of bottom-up, where you focus on the big picture and then drill down.&lt;/p&gt;
&lt;p&gt;A good way is to formulate a high-level plan, and creating outlines is a simple and effective way of getting some structure.
This may not be the best approach for a novel, but for the type of technical writing I do creating outlines has served me very well.&lt;/p&gt;
&lt;h2&gt;Organizing a book&lt;/h2&gt;
&lt;p&gt;On the highest level the chapter titles can serve to guide you (both the reader and the writer) through the book, and doubly so if you organize them in sections (real or imagined).
For example, even if you’ve never seen &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;my book&lt;/a&gt; before, the three main sections should give you a good idea on what the book is about and the journey it’ll take you through:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;What is a cryptocurrency?&lt;/strong&gt;&lt;br /&gt;
Properties of a cryptocurrency&lt;br /&gt;
How do cryptocurrencies work?&lt;br /&gt;
Look out for snake oil&lt;br /&gt;
What is money?&lt;br /&gt;
Are cryptocurrencies money?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better digital payments&lt;/strong&gt;&lt;br /&gt;
Cheaper &amp;amp; faster&lt;br /&gt;
“Undesirable” businesses&lt;br /&gt;
Freezing of merchant accounts&lt;br /&gt;
Uncensorable donations&lt;br /&gt;
For the unbanked&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A better currency&lt;/strong&gt;&lt;br /&gt;
The financial crisis, bad loans and bailouts&lt;br /&gt;
The blind leading the blind&lt;br /&gt;
A defective system&lt;br /&gt;
Private money&lt;br /&gt;
A global currency&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With this high-level outline all I had to do was to fill it in.
Yeah, that’s simplifying the reality a little, but it’s actually pretty close to how I wrote my book:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I had a bunch of ideas that I turned into chapters.&lt;/li&gt;
&lt;li&gt;I wrote one chapter at a time (not necessarily in order).&lt;/li&gt;
&lt;li&gt;I revised the planned chapters over time.&lt;/li&gt;
&lt;li&gt;I rewrote &lt;em&gt;a lot&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It may sound too simplistic and too perfect—surely you cannot plan so well that this is all there is to writing a book?
But remember that this is only a rough plan to guide you, in reality the process will be messy.
Moving, rewriting and throwing away chapters will be necessary.&lt;/p&gt;
&lt;h2&gt;Organizing chapters or blog posts&lt;/h2&gt;
&lt;p&gt;This approach with first creating an outline also works great inside the chapters or in a longer blog post.&lt;/p&gt;
&lt;p&gt;I may start with a simple list of things I want to say, but my goal is to turn that into headers and sub-headers.
As an example, these are the headers from the post &lt;a href=&quot;/blog/2023/03/14/battling_burnout/&quot;&gt;Battling burnout&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Is it burnout, depression or both?&lt;br /&gt;
No apparent reason&lt;br /&gt;
Red flags&lt;br /&gt;
Seeking help&lt;br /&gt;
What was the actual cause?&lt;br /&gt;
Things that helped me&lt;br /&gt;
The only thing that really helped me&lt;br /&gt;
Are you ever cured?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Burnout was quite a difficult subject for me to write about, and I didn’t know how to approach it.
But with an outline I got past the block and could start to chip away at the post.&lt;/p&gt;
&lt;h1&gt;Perfectionism is a blessing and a curse&lt;/h1&gt;
&lt;p&gt;On one hand it’s good to strive for perfectionism.
Even if you never reach it, the act of trying to make something as good as it can possibly be will increase the quality.&lt;/p&gt;
&lt;p&gt;But on the other hand, trying to be perfect may be a hindrance.
It may be paralyzing and I suspect it’s a big contributing factor for the famous “writer’s block”, where the writer is severely slowed down or even becoming unable to produce anything at all.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Perfect is the enemy of good&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I felt this effect after I had put way too much time designing the web version and the physical version of the book.
I think the result was really good; the book looks beautiful and is pleasing to read, but I burned out hard when I had to do it again with the eBook version.
2 years after the book was done, the eBook/PDF are still not available from regular stores, and truthfully I don’t know if I’ll ever gather the energy to do that.&lt;/p&gt;
&lt;p&gt;The problem is that my standard was (is?) too high.
I wanted it to look as good as possible, but chasing perfection only led to burnout.&lt;/p&gt;
&lt;p&gt;I’m still trying to be satisfied with things that are good enough instead of wanting perfection.
But it’s hard.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;To summarize, these are my main takeaways that &lt;em&gt;totally&lt;/em&gt; coincidentally corresponds to the headers in this post:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#writing-is-a-skill&quot;&gt;Writing is a skill that can be improved.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#consistency-is-the-most-important-thing&quot;&gt;Establishing a writing habit is crucial.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rewrite-rewrite-rewrite&quot;&gt;Rewriting is very important.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#clarity-of-thought-translates-into-clear-writing&quot;&gt;Clear up your thoughts to clear up your writing.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#have-a-plan-and-an-outline&quot;&gt;Outlining the book and chapters helps you and the reader.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#perfectionism-is-a-blessing-and-a-curse&quot;&gt;Don’t strive for perfection.&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I am by no means an authority on this matter; these are just some lessons that I learned when writing a book.&lt;/p&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Software</title><id>http://jonashietala.se/blog/2023/11/17/lets_build_a_voron_software/index.html</id><updated>2026-01-29T10:45:03+00:00</updated><link href="https://www.jonashietala.se/blog/2023/11/17/lets_build_a_voron_software" rel="alternate"/><published>2023-11-17T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The build continues, now in a little more familiar territory.&lt;/p&gt;
&lt;h1&gt;Firmware flashing&lt;/h1&gt;
&lt;p&gt;To flash the firmware I had to order a microSD card reader.
With that on hand the flashing wasn’t difficult. The &lt;a href=&quot;https://docs.vorondesign.com/build/software/&quot;&gt;VORON docs&lt;/a&gt; walks you through the installation very well.&lt;/p&gt;
&lt;h2&gt;Mainsail&lt;/h2&gt;
&lt;p&gt;I chose to install Mainsail instead of Fluidd simply because I liked the screenshot a little more.
From what I understand they’re very similar and the choice doesn’t really matter.
I flashed it using &lt;a href=&quot;https://www.raspberrypi.com/software/&quot;&gt;pi-imager&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was great to see the display turning on and being able to ssh to the Pi—such a relief!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/display_alive.jpg&quot; /&gt;
&lt;figcaption&gt;The Raspberry Pi and the display are alive and kicking, although the display is rotated 180 degress.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;After installing the Octopus firmware on it’s SD card and adding the device to &lt;code&gt;~/printer_data/config/printer.cfg&lt;/code&gt; I could start messing around with the Mainsail web interface.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[mcu]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;# This is my serial, not yours
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;serial: /dev/serial/by-id/usb-Klipper_stm32f446xx_140045000F50535556323420-if00
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/mainsail.png&quot; /&gt;
&lt;figcaption&gt;The Mainsail web interface.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;KlipperScreen&lt;/h2&gt;
&lt;p&gt;It’s good to see my old friend the Linux login prompt on the display, but that’s not really what we want here.
Instead we should install &lt;a href=&quot;https://klipperscreen.readthedocs.io/en/latest/&quot;&gt;KlipperScreen&lt;/a&gt; to be able to control the printer via a user-friendly UI.
I installed it using a &lt;a href=&quot;https://github.com/KlipperScreen/KlipperScreen/blob/master/docs/Installation.md#manual-install&quot;&gt;manual install&lt;/a&gt;, but in hindsight I maybe should’ve &lt;a href=&quot;https://github.com/dw-0/kiauh&quot;&gt;KIAUH&lt;/a&gt;. Oh well.&lt;/p&gt;
&lt;p&gt;To rotate the screen you edit &lt;code&gt;/boot/config.txt&lt;/code&gt; according to the &lt;a href=&quot;https://docs.ldomotors.com/en/guides/btt_43_rotate_guide&quot;&gt;LDO docs&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;# Make sure this line is commented
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;#dtoverlay=vc4-fkms-v3d
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;# Add these 2 lines to the end
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;display_lcd_rotate=2
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dtoverlay=rpi-ft5406,touchscreen-inverted-x=1,touchscreen-inverted-y=1
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/klipperscreen.jpg&quot; /&gt;
&lt;figcaption&gt;The display is rotated and uses KlipperScreen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Home Assistant&lt;/h2&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/trident_ha.png&quot; /&gt;
&lt;figcaption&gt;Home Assistant integration with plenty of controls and sensors.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Of course, I had to hook up the printer to &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;.
This was easily done using the &lt;a href=&quot;https://github.com/marcolivierarsenault/moonraker-home-assistant&quot;&gt;Moonraker Home Assistant&lt;/a&gt; plugin via HACS.&lt;/p&gt;
&lt;p&gt;Maybe I’ll actually make a functional dashboard with it… Some day.&lt;/p&gt;
&lt;h1&gt;Initial config&lt;/h1&gt;
&lt;p&gt;It’s not enough to install the firmware, there are quite a few things in &lt;code&gt;~/printer_data/config/printer.cfg&lt;/code&gt; that needs to be changed.
I used the &lt;a href=&quot;https://github.com/MotorDynamicsLab/LDOVoronTrident/tree/master/Firmware&quot;&gt;LDO config&lt;/a&gt; as a starting point and went from there.
To not bore you to death I’ll try to only document the noteworthy changes I made.&lt;/p&gt;
&lt;p&gt;And—very importantly—I installed Neovim on the Raspberry Pi I using &lt;a href=&quot;https://snapcraft.io/install/snapd/raspbian&quot;&gt;snapd&lt;/a&gt;.
While I have the configuration files in a git repo, it’s far easier to ssh and edit the files directly.&lt;/p&gt;
&lt;h2&gt;Be careful&lt;/h2&gt;
&lt;p&gt;As advised in the &lt;a href=&quot;https://docs.vorondesign.com/build/startup/&quot;&gt;VORON initial startup docs&lt;/a&gt; when testing these things (motors in particular) you should have a &lt;em&gt;tested&lt;/em&gt; way of stopping the printer if something goes wrong.
Like if you’re ramming the toolhead against the edge or something.&lt;/p&gt;
&lt;p&gt;I… Didn’t do this and just saw the “Home” button and thought—I wonder if it moves when I press this?&lt;/p&gt;
&lt;p&gt;Luckily the XY motors worked as expected (I hadn’t configured Z yet) but it could’ve been very bad.&lt;/p&gt;
&lt;h2&gt;Bed&lt;/h2&gt;
&lt;p&gt;The bed—through the SSR—is connected to &lt;code&gt;HE0&lt;/code&gt;, corresponding to the &lt;code&gt;PA2&lt;/code&gt; pin (&lt;code&gt;BED_OUT&lt;/code&gt; is &lt;code&gt;PA1&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[heater_bed]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;# SSR Pin - HE0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;heater_pin: PA2
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Hotend&lt;/h2&gt;
&lt;p&gt;The hotend is connected to the non-standard &lt;code&gt;HE1&lt;/code&gt; (since my cable didn’t come with a fork spade to connect it to &lt;code&gt;BED_OUT&lt;/code&gt;, as advised in the &lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron-trident/wiring_guide_250_rev_a&quot;&gt;LDO wiring docs&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[extruder]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;# Heater - HE1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;heater_pin: PA3
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;sensor_type: PT1000
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It also took a long time for me to figure out the correct &lt;code&gt;sensor_type&lt;/code&gt; value.
None of the values in the &lt;a href=&quot;https://www.klipper3d.org/Config_Reference.html#common-thermistors&quot;&gt;common thermistors&lt;/a&gt; documentation worked for the Phateus Rapido, but I found an off-hand comment somewhere that &lt;code&gt;PT1000&lt;/code&gt; was the correct type.&lt;/p&gt;
&lt;h2&gt;Tap&lt;/h2&gt;
&lt;p&gt;Configuring Tap was straightforward, I simply followed the steps in the &lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap/blob/main/config/tap_klipper_instructions.md&quot;&gt;Updating your Klipper config for Tap&lt;/a&gt; instructions.&lt;/p&gt;
&lt;p&gt;The one thing that confused me was this this line about &lt;code&gt;PROBE_CALIBRATE&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;You’ll need to manually calibrate the probe’s Z offset by using PROBE_CALIBRATE.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Turns out it’s the process described in &lt;a href=&quot;https://docs.vorondesign.com/build/startup/#z-offset-adjustment&quot;&gt;configuring the Z Offset Adjustment&lt;/a&gt; in the VORON documentation, only substituting &lt;code&gt;Z_ENDSTOP_CALIBRATE&lt;/code&gt; with &lt;code&gt;PROBE_CALIBRATE&lt;/code&gt;. I ended up with this line in the config:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;#*# [probe]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;#*# z_offset = -1.195
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To see if Tap is working I warmed up the enclosure a little bit I ran &lt;code&gt;PROBE_ACCURACY&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;probe accuracy results:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    maximum -1.219375, minimum -1.221250, range 0.001875,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    average -1.220500, median -1.220625, standard deviation 0.000612
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap&quot;&gt;According to the docs&lt;/a&gt; the standard deviation falls within the expected range of a well-built machine:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;For well-built machines you can expect to see between 0.0000 and 0.0008 standard deviation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I doubt that I built everything that well, but I’ll take it!&lt;/p&gt;
&lt;p&gt;I’m a little confused what the negative numbers mean; is my &lt;code&gt;z_offset&lt;/code&gt; too low, causing the probe values to be negative?
Or are they uncorrelated and this is completely fine?&lt;/p&gt;
&lt;h2&gt;Extruder&lt;/h2&gt;
&lt;p&gt;It’s weird.
In some cases you can move mountains and solve the most difficult problems in a flash, but at other times you’ll stumble on the smallest pebble.&lt;/p&gt;
&lt;p&gt;And I stumbled hard on inserting filament into the extruder.&lt;/p&gt;
&lt;p&gt;I know I checked it when assembling the Clockwork 2, but by god I couldn’t get it to grab on the filament.
After a long time of fiddling, and considering if I should just disassemble it all, I somehow got it to work.&lt;/p&gt;
&lt;p&gt;I think it was a combination of the extruder direction being inverted and some filament getting stuck, but I just don’t know.
I’ll file it under user error and forget about it.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[extruder]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dir_pin: PF0 # Inverted by removing the `!`
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don’t understand how you’re supposed to properly measure the amount of filament when calibrating
the extruder, the VORON docs isn’t particularly clear about it.
What I did was to pull it taught and try to measure from there, but I fear it wasn’t &lt;em&gt;that&lt;/em&gt; precise.&lt;/p&gt;
&lt;p&gt;Maybe it would be easier without the top panel?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/extrude_calibration2.jpg&quot; /&gt;
&lt;figcaption&gt;The small red mark was 100mm away from the edge of the black holder part before I tried to extrude 100mm of filament. I think this is good enough?&lt;/figcaption&gt;
&lt;/figure&gt;&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[extruder]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;rotation_distance: 20.41105599   # After recalibration
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/extrude_calibration.jpg&quot; /&gt;
&lt;figcaption&gt;I hope my first print will look better than this mess?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Panel mounting&lt;/h1&gt;
&lt;p&gt;You may have noticed that the above pictures had panels on them.
That’s right, to be able to heat soak the printer I had to have the panels, so I quickly installed them.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/front_mounting.jpg&quot; /&gt;
&lt;figcaption&gt;It was easier to align the doors with the printer lying down.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/front_magnet_mount.jpg&quot; /&gt;
&lt;figcaption&gt;How are you supposed to get the right polarity and stick the part on the correct spot on the door? Just place the magnet and then push in the part.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve been impressed with the build so far, but I’m not impressed with the doors.
The doors doesn’t have foam tape between them and the frame unlike the rest of the panels.&lt;/p&gt;
&lt;p&gt;I wonder why that is?
I worry that they will scramble against the frame and it won’t make a good seal, which I think could’ve been avoided.
I’ll probably look for mods for the doors; maybe I’ll replace the doors with a magnetically mounted panel or something.&lt;/p&gt;
&lt;h1&gt;Slicer&lt;/h1&gt;
&lt;p&gt;I do feel my 3D printing inexperience when I have to setup yet another thing: a slicer.
There are quite a few options, but I didn’t care to try out them all—I simply wanted to get up and running smoothly.&lt;/p&gt;
&lt;p&gt;I picked &lt;a href=&quot;https://github.com/supermerill/SuperSlicer&quot;&gt;SuperSlicer&lt;/a&gt; because it works on Linux, has a custom &lt;a href=&quot;https://github.com/VoronDesign/Voron-2/tree/Voron2.4/slicer_profiles/PrusaSlicer&quot;&gt;Voron Design profile&lt;/a&gt; to import, and seems fairly popular.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/superslicer.png&quot; /&gt;
&lt;figcaption&gt;Viewing the layers is weirdly satisfying.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I was initially super confused on how to see the layer preview.
Turns out there was some error with only using the preconfigured Voron v1 250 0.4mm config I selected in the configuration wizard.
Importing the &lt;a href=&quot;https://github.com/VoronDesign/Voron-2/tree/Voron2.4/slicer_profiles/PrusaSlicer&quot;&gt;Voron Design profile&lt;/a&gt; and selecting it seems to have resolved the issue.&lt;/p&gt;
&lt;h1&gt;What’s left?&lt;/h1&gt;
&lt;p&gt;The next thing is finally &lt;strong&gt;to print something&lt;/strong&gt;.
Unfortunately I don’t have any filament other than the small sample that came with the LDO kit, so it’s back to waiting for a shipment to be delivered.&lt;/p&gt;
&lt;p&gt;And after that there are still things left to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I’m missing some printed parts that I need to print out myself.&lt;/p&gt;
&lt;p&gt;For example I need a rear exhaust cover (although I plan to add a HEPA filter there) and spacers to mount the handles.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tuning, tuning and more tuning.&lt;/p&gt;
&lt;p&gt;Prints needs to look good.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mod it.&lt;/p&gt;
&lt;p&gt;It feels wrong to build an incredibly moddable printer and leave it without any mods.
I’m trying not to keep the “to-mod list” short but I can already sense that I’ll fail miserably.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/full_with_panels.jpg&quot; /&gt;
&lt;figcaption&gt;It works, but it’s not done yet.&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Let&apos;s build a VORON: Wiring</title><id>http://jonashietala.se/blog/2023/11/11/lets_build_a_voron_wiring/index.html</id><updated>2026-01-29T10:45:31+00:00</updated><link href="https://www.jonashietala.se/blog/2023/11/11/lets_build_a_voron_wiring" rel="alternate"/><published>2023-11-11T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;&lt;blockquote&gt;Dread it. Run from it. Wiring arrives all the same.&lt;/blockquote&gt;&lt;/div&gt;
&lt;p&gt;It’s time for the part of my VORON build that I’ve been dreading: the wiring.&lt;/p&gt;
&lt;p&gt;It’s scary because I really have no clue what I’m doing, and mistakes can be very costly and time-consuming.&lt;/p&gt;
&lt;p&gt;I’ve taken my time to double- and triple-check everything, and I took lots of pictures.
I ran into some issues I’ll document here, but this post will mostly be filled with pictures to gawp at.&lt;/p&gt;
&lt;h1&gt;Cable chains&lt;/h1&gt;
&lt;p&gt;There wasn’t a ton of instructions on the cable chains, but I felt it went well.&lt;/p&gt;
&lt;aside&gt;I made some big mistakes here that caused major headache later on, but &lt;a href=&quot;#lack-of-range-for-the-toolhead&quot;&gt;more on that later&lt;/a&gt;.&lt;/aside&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/chain3.jpg&quot; /&gt;
&lt;figcaption&gt;It was fiddly, but not the end of the world.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/chain1.jpg&quot;&gt;&lt;img src=&quot;/images/trident/chain1.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/chain2.jpg&quot;&gt;&lt;img src=&quot;/images/trident/chain2.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/loose_top.jpg&quot; /&gt;
&lt;/figure&gt;&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/hidden_side.jpg&quot;&gt;&lt;img src=&quot;/images/trident/hidden_side.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/hidden_side_chain.jpg&quot;&gt;&lt;img src=&quot;/images/trident/hidden_side_chain.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/top_motor_cables.jpg&quot; /&gt;
&lt;figcaption&gt;If we make the wires pretty from the start, we can just continue like that?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Main power&lt;/h1&gt;
&lt;p&gt;Yes, I guess I should’ve connected main power before connecting the motor cables, but the octopus isn’t connected yet so it’s fine…&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/mains.jpg&quot; /&gt;
&lt;figcaption&gt;I triple-checked that I don’t mix colors and I checked again that I connected it to the outlet properly.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that it says “TO 5V PSU” on the PSU cable. I think that’s a typo…&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/mains_light.jpg&quot; /&gt;
&lt;figcaption&gt;The green light turns on! I’m glad it didn’t burn up yet…&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Octopus power&lt;/h1&gt;
&lt;p&gt;According to the docs, the SSR should connect to &lt;code&gt;HE0&lt;/code&gt; instead of &lt;code&gt;BED_OUT&lt;/code&gt;. Fine.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/octo_power.jpg&quot; /&gt;
&lt;figcaption&gt;The Octopus has the required power, but I didn’t check if it turns on at this point…&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/octo_power2.jpg&quot; /&gt;
&lt;figcaption&gt;I mixed the 3 and 4 inputs on the SSR, but luckily I caught it when double or triple-checking.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Breakout cables&lt;/h1&gt;
&lt;p&gt;I’m following LDO’s wiring guide and the breakout cables are next.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/breakout1.jpg&quot;&gt;&lt;img src=&quot;/images/trident/breakout1.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/breakout2.jpg&quot;&gt;&lt;img src=&quot;/images/trident/breakout2.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;h2&gt;Wrong hotend cable?&lt;/h2&gt;
&lt;p&gt;When I was about to connect the hotend cable I noticed a problem.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron-trident/wiring_guide_250_rev_a&quot;&gt;wiring guide&lt;/a&gt; it says that I should connect the hotend to &lt;code&gt;BED_OUT&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Breakout PCB&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cable label (breakout)&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Controller&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cable label (controller)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;HE0 ****&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;HE0&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;HE0/PA2&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;BED_OUT&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;****The BED_OUT port in the Octopus controller carries more current than the HE ports, this allows you to use super high power hotends such as the Phaetus Rapido.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But the cable that I got doesn’t fit:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/wrong_hotend_cable.jpg&quot; /&gt;
&lt;figcaption&gt;The hotend cable has “pin” type connectors.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/right_cable_connector.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;What I want is “U” type connectors.
(I later found them on Amazon as “fork spade” terminals.)&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My suspicion is that I got the wrong cable because the &lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron2/wiring_guide_rev_c&quot;&gt;V2.4 wiring guide&lt;/a&gt; specifies that the cable goes into &lt;code&gt;HE0&lt;/code&gt; and &lt;code&gt;SSR&lt;/code&gt; goes to &lt;code&gt;BED_OUT&lt;/code&gt;, while the Trident has it reversed.&lt;/p&gt;
&lt;p&gt;I complained about this to 3DJake (where I bought the kit from), who reached out to LDO where I got the response that they’re sorry, but I can connect the hotend to &lt;code&gt;HE1&lt;/code&gt; and change something in &lt;code&gt;printer.cfg&lt;/code&gt; to make it work.&lt;/p&gt;
&lt;p&gt;Not ideal as I do have the Phaetus Rapido, and according to LDO’s &lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron2/kit-errata&quot;&gt;V2.4 errata&lt;/a&gt; it’s advisable to switch:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;It has been reported that the Rapido hotend (by Phaetus) draws a large amount of current during initial heat-up. If you are using this hotend with our kit, please consider swapping the bed and hotend connections at the Octopus side.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’m not thrilled about it, but I guess I need to find some spade terminals and change the wires later.&lt;/p&gt;
&lt;h2&gt;Full picture&lt;/h2&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/breakout.jpg&quot; /&gt;
&lt;figcaption&gt;A better overview of the wiring with breakout cables (and other things).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Raspberry&lt;/h1&gt;
&lt;p&gt;The Raspberry Pi uses 5V from the Octopus via some PCBs:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/raspberry.jpg&quot; /&gt;
&lt;figcaption&gt;The Raspberry Pi is connected.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Other small details&lt;/h1&gt;
&lt;p&gt;The major things are done, but there are more things that needs to be fixed.&lt;/p&gt;
&lt;h2&gt;LEDs&lt;/h2&gt;
&lt;p&gt;I got a cute little PCB for connecting two LED strips in the kit.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/led_pcb.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;It’s neat. I like it.
(I later moved the LED wire so it goes down in the front instead of behind the belts.)&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/leds_mounted.jpg&quot; /&gt;
&lt;figcaption&gt;I wasn’t sure how to mount the LEDs, so I added a wire cover below the LED strips to give it a platform to attach on.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Controller fan&lt;/h2&gt;
&lt;p&gt;I should’ve gotten another PCB mount to mount the fan PCB, but I didn’t get one from the print-it-forward service.
Maybe I should’ve mounted the fan PCB with the mount instead of the LED PCB, but I couldn’t be bothered.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/fan_pcb.jpg&quot; /&gt;
&lt;figcaption&gt;Some tape to prevent shorts.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/fan_pcb2.jpg&quot; /&gt;
&lt;figcaption&gt;It was hell to get it mounted. Why didn’t I do this before adding wires…?&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/remove_wire_first.jpg&quot; /&gt;
&lt;figcaption&gt;The wire is stuck between the fan and the plastic part, oops.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Display mount&lt;/h2&gt;
&lt;p&gt;I didn’t manage to get the display mount to work properly.
The screws didn’t align properly and the display cover constantly fell off.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/mount2.jpg&quot; /&gt;
&lt;figcaption&gt;There’s a space here that I couldn’t close no matter how hard I pushed.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/mount_bad.jpg&quot; /&gt;
&lt;figcaption&gt;The screw hole is slightly off.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I had to use tape to keep it all together:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/mount_bad3.jpg&quot; /&gt;
&lt;figcaption&gt;Tape for the cover so it doesn’t fall off.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/mount_bad4.jpg&quot; /&gt;
&lt;figcaption&gt;Tape for the sides.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It works I guess but I need to print new mounts when I get the printer up and running.
I believe the problem is that I have the 2.1 version of the display, while the mount is for the 2.0 version.&lt;/p&gt;
&lt;h2&gt;The bed&lt;/h2&gt;
&lt;p&gt;I had delayed installing the bed, but with the wiring needing to be done it was time to install the bed.&lt;/p&gt;
&lt;p&gt;I was a bit worried about applying the magnetic sheet, but I think I managed to do it without any bubbles.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/bed_wired.jpg&quot; /&gt;
&lt;figcaption&gt;The bed is installed and ready.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Maybe the Z-endstop is completely unnecessary as I’m going to run Tap?
Probably, but as it’s already installed I won’t bother ripping it out now.&lt;/p&gt;
&lt;h2&gt;Missing Toolhead cables&lt;/h2&gt;
&lt;p&gt;When &lt;a href=&quot;/blog/2023/10/18/lets_build_a_voron_toolhead/#stealthburner-assembly&quot;&gt;assembling the stealthburner&lt;/a&gt; I couldn’t connect the hotend to the toolhead PCB because the connectors didn’t match, and I also didn’t have a cable from the Tap PCB to the toolhead PCB.
It was time to rectify that.&lt;/p&gt;
&lt;p&gt;I didn’t do it when building the toolhead because I didn’t have the tools for it.
So I ordered wire strippers, a crimping tool, JST connectors and some wire from Amazon.&lt;/p&gt;
&lt;aside&gt;No, I didn’t have a wire stripper and I’ve never created a cable before.&lt;/aside&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/crimp.jpg&quot; /&gt;
&lt;figcaption&gt;Crimping was fiddly but after a dozen attempts I think I got it down.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;After I painstakingly created the Tap cable—with a 3-pin JST on each end—I noticed that the Tap PCB required a smaller connector than the ones I had. Oh no… Do I have to order &lt;em&gt;another&lt;/em&gt; connector kit?&lt;/p&gt;
&lt;p&gt;But luckily the Tap kit came with one such connector.
(Please don’t break it.)&lt;/p&gt;
&lt;p&gt;So I tried to change it… But after trying for some time I noticed that the wires I had were too thick, and didn’t fit this smaller connector.
I nearly destroyed the connector while trying to insert the wires…&lt;/p&gt;
&lt;p&gt;Things aren’t going my way, maybe I need to order (and wait for) new wire?&lt;/p&gt;
&lt;p&gt;But wait!&lt;/p&gt;
&lt;p&gt;Remember how I complained about the hotend cables having the wrong connector?
Turns out the Rapido comes with extension cables with the connectors I wanted.
The thermistor extension cable has thinner wires and the same JST connector I have…&lt;/p&gt;
&lt;p&gt;Maybe I could shorten that cable and use the leftover wire for the Tap cable?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/short_cable.jpg&quot; /&gt;
&lt;figcaption&gt;A shortened extension cable for the hotend thermistor.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/own_cable.jpg&quot; /&gt;
&lt;figcaption&gt;Behold! My glorious cable!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve spent an embarrassing amount of time and energy just to create this single cable.
It makes me &lt;em&gt;really&lt;/em&gt; appreciate that the LDO kit comes with pre-made wiring,
I can’t imagine the frustration if I had to create all wiring from scratch (there’s a &lt;em&gt;lot&lt;/em&gt; of it).&lt;/p&gt;
&lt;p&gt;One problem I still have is the excessive wiring coming out from the toolhead, and I don’t really know what to do with it.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/cable_bundle2.jpg&quot; /&gt;
&lt;figcaption&gt;Too many cables. Should I try to hide it inside the cable chain?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Maybe I could try to shorten them all…
But I’m not skilled or brave enough to try.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/cable_bundle.jpg&quot; /&gt;
&lt;figcaption&gt;It’s not pretty… It sort of ruins the nice looking toolhead don’t you think?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Gantry racking&lt;/h1&gt;
&lt;p&gt;When building the printer I’ve been jumping around a little, and somewhere in the middle of the wiring I decided I should try to &lt;a href=&quot;https://www.youtube.com/watch?v=cOn6u9kXvy0&quot;&gt;solve the gantry racking&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had noticed that the gantry catches a little when moving it around, and I got a tip from the &lt;a href=&quot;https://forum.vorondesign.com/&quot;&gt;VORON forum&lt;/a&gt; that I should rack the gantry to try to fix it.&lt;/p&gt;
&lt;p&gt;And it did solve the issue!
The movement isn’t as smooth as in &lt;a href=&quot;https://www.youtube.com/watch?v=cOn6u9kXvy0&quot;&gt;NERO 3D’s video&lt;/a&gt;, but at least it doesn’t catch anywhere.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;I did this with the motors and everything connected, which is NOT recommended as it may damage the components.
At one point I saw the display flashing and thought “huh, that’s weird”, but clueless as I am the implications didn’t register at that time.&lt;/p&gt;
&lt;p&gt;Yeah I know that NERO 3D said to watch out for it in the gantry racking video, but it had slipped my mind.
Now I’m really worried that I’ve screwed myself over in a major way.&lt;/p&gt;
&lt;/aside&gt;
&lt;h1&gt;Lack of range for the toolhead&lt;/h1&gt;
&lt;p&gt;After installing the bed and racking the gantry, I noticed a big issue with the toolhead: it doesn’t reach the corners of the bed and the bed doesn’t reach up to the toolhead.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/short_x.jpg&quot; /&gt;
&lt;figcaption&gt;The toolhead is at max x, but it’s far from the edge.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/short_y.jpg&quot; /&gt;
&lt;figcaption&gt;The toolhead doesn’t reach the edge on the y-axis either.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/short_z.jpg&quot; /&gt;
&lt;figcaption&gt;I tried to raise the bed as high as possible, but it doesn’t come close to the toolhead, let alone raising it for tap to function.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Turns out I had made a mistake when installing the cable chains, as they’re all too short and they max out too soon, stopping the movement.&lt;/p&gt;
&lt;p&gt;There were 4 extra links in the kit, but I didn’t know what to do with them so I forgot about them and took for granted that the three cable chains would work as-is.
Maybe this is assumed knowledge, but when installing them—and before running the wires through—I should’ve checked the range of motion to be sure they were long enough.&lt;/p&gt;
&lt;p&gt;Now I had to break open the chains and add the extra links afterwards.
This was super annoying because I had to pull more wire to the chains, meaning I had to undo all the wiring work for all the motors and toolhead cables.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/redo_chain.jpg&quot; /&gt;
&lt;figcaption&gt;Opening up the xy cable chains.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I added two links to the z chain and one link each to the x and y chains.
For x and y I also had to add some extra space by offsetting them so the chains aren’t flush to the edge of the extrusion holder or toolhead.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/redo_chain2.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;I had to add some extra spacing on the x and y chains to get the required range of motion.
I wish I hadn’t clipped away the tab, so I could zip tie the cables to it.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/redo_chain3.jpg&quot;&gt;&lt;img src=&quot;/images/trident/redo_chain3.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/redo_chain4.jpg&quot;&gt;&lt;img src=&quot;/images/trident/redo_chain4.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;h1&gt;It’s all coming together&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/full_wiring.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;All the wiring is in place.
(You may notice an unconnected cable in the upper right, it’s for the Nevermore filter I haven’t built yet).&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I may clean it up a bit after I’ve verified that things work.
It may not be &lt;a href=&quot;https://www.reddit.com/r/cableporn/&quot;&gt;r/cableporn&lt;/a&gt; neat, but it could be worse.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/nice_wires2.jpg&quot; /&gt;
&lt;figcaption&gt;A better overview of the wiring with skirts and all.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Let there be light&lt;/h1&gt;
&lt;p&gt;With everything prepared I closed my hands, curled my toes, and clenched my ass and turned on the power…&lt;/p&gt;
&lt;p&gt;And the lights are glowing! &lt;em&gt;Huzzah!&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/octopus_lights.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;The lights are glowing, and there’s no smoke from the Octopus.
I disconnected the hotend and Raspberry as a safety measure before turning it on.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/trident/pi_lights.jpg&quot; /&gt;
&lt;figcaption&gt;The Raspberry Pi also has some lights when turned on.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The status lights are promising, but I can’t tell for sure before flashing.&lt;/p&gt;
</content></entry><entry><title>I designed my own keyboard layout. Was it worth it?</title><id>http://jonashietala.se/blog/2023/11/02/i_designed_my_own_keyboard_layout_was_it_worth_it/index.html</id><updated>2024-11-27T09:30:28+00:00</updated><link href="https://www.jonashietala.se/blog/2023/11/02/i_designed_my_own_keyboard_layout_was_it_worth_it" rel="alternate"/><published>2023-11-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Almost two and a half years ago I embarked on the journey to change keyboard layout.
At first I tried out existing ones, but it didn’t take long before I figured it’s better to develop my own—and things went downhill fast from there.&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/neighbour_combos.svg&quot;&gt;
&lt;figcaption&gt;(Some) &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Combos&quot; title=&quot;The current T-34 keyboard layout: Combos&quot;&gt;combos&lt;/a&gt; of the &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/&quot; title=&quot;The current T-34 keyboard layout&quot;&gt;T-34 layout&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;But now that I haven’t made any changes to the layout for over a year, I think it’s time for some introspection and ask the dreaded question: was it worth it?
And should you—the dear reader—do the same?&lt;/p&gt;
&lt;section id=&quot;What-were-my-goals-in-creating-my-own&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#What-were-my-goals-in-creating-my-own&quot; class=&quot;heading-ref&quot;&gt;What were my goals in creating my own?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I essentially had two big goals with my layout:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Relieve my RSI&lt;/p&gt;
&lt;p&gt;I had started to develop RSI in my right hand that I really wanted to cure.
Especially in the area of my right thumb, I wanted to relieve my right hand in general.&lt;/p&gt;
&lt;p&gt;I also wanted to reduce pinky usage—particularly for my right pinky that I had broken earlier and felt very weak.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optimized for my usage&lt;/p&gt;
&lt;p&gt;I had three main use-cases I wanted to optimize for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Vim usage
&lt;/li&gt;
&lt;li&gt;
Write Swedish and English
&lt;/li&gt;
&lt;li&gt;
Coding in a myriad of different programming languages
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Did-I-succeed-with-the-goals&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Did-I-succeed-with-the-goals&quot; class=&quot;heading-ref&quot;&gt;Did I succeed with the goals?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the first I can say that in combination with the &lt;a href=&quot;https://github.com/pierrechevalier83/ferris&quot;&gt;Ferris&lt;/a&gt;—a split keyboard with 34 keys—my RSI did indeed get a lot better.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/uses/ferris.jpg&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;https://github.com/pierrechevalier83/ferris&quot;&gt;Ferris&lt;/a&gt;, my keyboard that helps with RSI.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;As for the second—if it’s optimized for my usage—I don’t really know how to answer.
When I was in the middle of designing the layout I probably would’ve pointed out the low SFB values (Same Finger Bigram), the redirects and &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/#Symbols&quot; title=&quot;The current T-34 keyboard layout: Symbols&quot;&gt;generated interesting graphs&lt;/a&gt; and &lt;a href=&quot;/blog/2022/08/28/the_t-342_keyboard_layout/#more-heatmaps&quot; title=&quot;The T-34/2 keyboard layout: More heatmaps&quot;&gt;heatmaps&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34-crazy.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;But now I’m satisfied with saying that it just &lt;strong&gt;feels really good&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;You-have-to-be-a-little-crazy&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#You-have-to-be-a-little-crazy&quot; class=&quot;heading-ref&quot;&gt;You have to be a little crazy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s quite extreme to design your own layout and I think you have to be a little crazy to do it.
I know I was.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There I was; awake in the middle of the night carrying our baby in a harness, standing in front of the computer trying to learn this new stinking layout while ignoring his cute smile, hoping he would fall asleep soon.&lt;/p&gt;
&lt;p&gt;I was trying to learn the &lt;a href=&quot;https://deskthority.net/wiki/BEAKL#BEAKL_15&quot; title=&quot;BEAKL 15 keyboard layout&quot;&gt;BEAKL 15&lt;/a&gt; layout but it just wasn’t working for me.
Maybe I could tweak it a little—so I did.
Maybe I could tweak it some more? I did that too.&lt;/p&gt;
&lt;p&gt;Eventually the sleep deprivation took over and I abandoned it and started to design my own layout.&lt;/p&gt;
&lt;p&gt;And that’s how I mostly designed my layout: I designed, tweaked and learned it in the middle of the night as I was trying to get our little kid to sleep.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I don’t think you have to be crazy to design a keyboard layout—but it probably helps to overcome the healthy fear of overoptimization and diminishing returns.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;What-could-I-have-done-differently&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#What-could-I-have-done-differently&quot; class=&quot;heading-ref&quot;&gt;What could I have done differently?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m not motivated to make any large changes or experiments with the layout now, but there are some things I wish I had tried out more:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.qmk.fm/#/one_shot_keys&quot; title=&quot;QMK one-shot keys&quot;&gt;One shot&lt;/a&gt; shift on the thumb instead of &lt;code&gt;E&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.qmk.fm/#/one_shot_keys&quot; title=&quot;QMK one-shot keys&quot;&gt;one shot&lt;/a&gt; shift seems like such a fantastic feature, but that would require me to move &lt;code&gt;E&lt;/code&gt; away from the thumb, which would snowball into an entirely different layout.&lt;/p&gt;
&lt;p&gt;Using a combo for &lt;a href=&quot;https://docs.qmk.fm/#/one_shot_keys&quot; title=&quot;QMK one-shot keys&quot;&gt;one shot&lt;/a&gt; shift is another thing I’d like to try that wouldn’t be too invasive.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://precondition.github.io/home-row-mods&quot; title=&quot;A guide to home row mods&quot;&gt;Home-row mods&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://precondition.github.io/home-row-mods&quot; title=&quot;A guide to home row mods&quot;&gt;Home-row mods&lt;/a&gt; is another very popular feature that would unlock a lot of extra space on the keyboard (as it would allow secondary effects on long-press instead of shifting and reduce the amount of combos I have).&lt;/p&gt;
&lt;p&gt;I did try it out a little bit, but maybe I could get used to it with more effort?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;32 keys instead of 34.&lt;/p&gt;
&lt;p&gt;It would be fairly simple to go down to 32 keys, with only a single key for each thumb.
The idea appeals to me, but I don’t think there are any practical benefits for me to do so.
I might do it in the future if/when I build a new keyboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More practice.&lt;/p&gt;
&lt;p&gt;I’m not close to my old QWERTY speed of +120 wpm simply because I got bored of practicing typing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Would-I-recommend-you-to-create-your-own-layout&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Would-I-recommend-you-to-create-your-own-layout&quot; class=&quot;heading-ref&quot;&gt;Would I recommend you to create your own layout?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s summon &lt;a href=&quot;https://en.wikipedia.org/wiki/Betteridge%27s_law_of_headlines&quot; title=&quot;Wikipedia: Betteridge&apos;s lay of headlines&quot;&gt;Betteridge’s law of headlines&lt;/a&gt; that says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any headline that ends in a question mark can be answered by the word &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I wouldn’t go quite that far, but you need to realize that there’s very real diminishing returns of completely designing your own layout.&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;vast&lt;/strong&gt; majority of cases it would be good enough to switch to something like &lt;a href=&quot;https://colemakmods.github.io/mod-dh/&quot; title=&quot;Colemak-DH keyboard layout&quot;&gt;Colemak-DH&lt;/a&gt; or &lt;a href=&quot;https://sites.google.com/alanreiser.com/handsdown&quot; title=&quot;Hands Down keyboard layout&quot;&gt;Hands Down&lt;/a&gt;, and depending on what you’re after switching to a more ergonomical keyboard would probably suffice.&lt;/p&gt;
&lt;p&gt;Or maybe not do anything at all. Lot’s of people have been happy with a regular keyboard and QWERTY.&lt;/p&gt;
&lt;section id=&quot;When-should-I-make-a-change&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#When-should-I-make-a-change&quot; class=&quot;heading-ref&quot;&gt;When should I make a change?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I think it comes down to two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
What benefits are you looking for?
&lt;/li&gt;
&lt;li&gt;
How motivated are you?
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First an important note: changing the layout because you want to type faster will probably not work out.
Chances are you’ve been using QWERTY for many years and the amount of practice you need to catch up to and surpass your QWERTY speed will be &lt;strong&gt;staggering&lt;/strong&gt;.
Most will burn out long before reaching that point (including me).&lt;/p&gt;
&lt;p&gt;The biggest benefit I see with an alternative layout is comfort.
If you’re worried about RSI, and you foresee yourself spending a few decades more in front of the computer, then switching layout might be a good idea.&lt;/p&gt;
&lt;p&gt;Another benefit is if you have some special requirements with your layout.
In my case for example I wanted to be able to comfortably type Swedish on a tiny keyboard, and just using &lt;a href=&quot;https://colemakmods.github.io/mod-dh/&quot; title=&quot;Colemak-DH keyboard layout&quot;&gt;Colemak-DH&lt;/a&gt; or something wouldn’t really support that well because I couldn’t fit &lt;code&gt;åäö&lt;/code&gt; on the base layer.&lt;/p&gt;
&lt;p&gt;But with my own layout I could have &lt;code&gt;åäö&lt;/code&gt; &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Swedish-overlay&quot; title=&quot;The current T-34 keyboard layout: Swedish overlay&quot;&gt;easily accessible&lt;/a&gt; (by toggling between &lt;code&gt;()_&lt;/code&gt; and &lt;code&gt;åäö&lt;/code&gt; with a layer).&lt;/p&gt;
&lt;p&gt;And of course, if you find the idea of designing your own layout interesting or fun, you should totally do it!
I honestly thought it was &lt;strong&gt;&lt;strong&gt;really fun&lt;/strong&gt;&lt;/strong&gt; (even though learning it was a pain).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;A-layout-is-more-than-alpha-characters&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#A-layout-is-more-than-alpha-characters&quot; class=&quot;heading-ref&quot;&gt;A layout is more than alpha characters&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_SYM.svg&quot;&gt;
&lt;figcaption&gt;Symbols are very important for a programmer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Something that people seem to miss with alternative layouts—even people designing them—is that a layout is much more than where the alpha characters goes.&lt;/p&gt;
&lt;p&gt;I’ve spent much more time on where to &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/#Symbols&quot; title=&quot;The current T-34 keyboard layout: Symbols&quot;&gt;place the symbols&lt;/a&gt;, how to &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Numbers&quot; title=&quot;The current T-34 keyboard layout: Numbers&quot;&gt;handle numbers&lt;/a&gt;, what type of &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Modifiers&quot; title=&quot;The current T-34 keyboard layout: Modifiers&quot;&gt;modifiers&lt;/a&gt; I want, a &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Navigation-layer&quot; title=&quot;The current T-34 keyboard layout: Navigation layer&quot;&gt;navigation layer&lt;/a&gt;, and &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#One-handed-Shortcuts&quot; title=&quot;The current T-34 keyboard layout: One-handed shortcuts&quot;&gt;shortcuts&lt;/a&gt; than the base layer, and that’s also where most of the benefit of my layout comes from.&lt;/p&gt;
&lt;p&gt;Symbols for example are very dependent on the programming languages you use, so there’s lots of benefit to a symbols layer optimized for those. It’s much more productive to spend time on optimizing symbols placement than to try to improve &lt;a href=&quot;https://colemakmods.github.io/mod-dh/&quot; title=&quot;Colemak-DH keyboard layout&quot;&gt;Colemak-DH&lt;/a&gt;, which is already pretty darn good.&lt;/p&gt;
&lt;p&gt;Even simple things like adding a &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Navigation-layer&quot; title=&quot;The current T-34 keyboard layout: Navigation layer&quot;&gt;navigation layer&lt;/a&gt; (with arrow keys under your fingertips) or moving Escape are hugely beneficial.
And of course, avoiding the gymnastics of pressing Ctrl in the lower left corner with the pinky is a big win.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;My-recommendation&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#My-recommendation&quot; class=&quot;heading-ref&quot;&gt;My recommendation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want to make a change to your setup, these are my recommendations sorted from least to most effort:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Get a programmable keyboard.&lt;/p&gt;
&lt;p&gt;For example, moving Escape to Caps Lock and &lt;a href=&quot;https://docs.qmk.fm/#/mod_tap&quot; title=&quot;QMK mod tap&quot;&gt;behave like Ctrl when held&lt;/a&gt; are great modifications for a regular keyboard. (You might be able to do that on the OS level too.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get a more ergonomical keyboard.&lt;/p&gt;
&lt;p&gt;I think a split keyboard with tenting is a great start.
If you want to go the extra length try to make it smaller.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tweak the big buttons to avoid large and awkward motions.&lt;/p&gt;
&lt;p&gt;For a Vim user, remapping Escape is a classic.
Ctrl, Shift, Alt, and Enter are also good candidates for moving to a thumb button, a &lt;a href=&quot;https://docs.qmk.fm/#/feature_combo&quot; title=&quot;QMK combos&quot;&gt;combo&lt;/a&gt; or a &lt;a href=&quot;https://docs.qmk.fm/#/mod_tap&quot; title=&quot;QMK mod tap&quot;&gt;Mod-Tap&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Navigation-layer&quot; title=&quot;The current T-34 keyboard layout: Navigation layer&quot;&gt;navigation layer&lt;/a&gt; (or &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Workspace-layer&quot; title=&quot;The current T-34 keyboard layout: Workspace layer&quot;&gt;two&lt;/a&gt; or &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/#Windows-layer&quot; title=&quot;The current T-34 keyboard layout: Windows layer&quot;&gt;three&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start tweaking the symbols and numbers (and other things you can come up with).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use an alternative layout such as &lt;a href=&quot;https://colemakmods.github.io/mod-dh/&quot; title=&quot;Colemak-DH keyboard layout&quot;&gt;Colemak-DH&lt;/a&gt;, &lt;a href=&quot;https://sites.google.com/alanreiser.com/handsdown&quot; title=&quot;Hands Down keyboard layout&quot;&gt;Hands Down&lt;/a&gt; or &lt;a href=&quot;https://mathematicalmulticore.wordpress.com/the-keyboard-layout-project/&quot; title=&quot;MTGAP 2.0 keyboard layout&quot;&gt;MTGAP 2.0&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make your own completely custom layout.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You don’t have to do everything at once and you can try out the different levels to see how painful and time consuming the changes are.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;How-do-you-even-learn-a-new-layout&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#How-do-you-even-learn-a-new-layout&quot; class=&quot;heading-ref&quot;&gt;How do you even learn a new layout?&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_BASE.svg&quot;&gt;
&lt;figcaption&gt;The &lt;a href=&quot;/blog/2022/09/06/the_current_t-34_keyboard_layout/&quot; title=&quot;The current T-34 keyboard layout&quot;&gt;T-34&lt;/a&gt; base layer. There’s not a trace of QWERTY left.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Say that you’ve decided to learn a new layout. Now what?&lt;/p&gt;
&lt;p&gt;The simple answer is that you just need to practice.
But here are some tips to make the process more efficient:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Don’t look at a reference of the layout and use blank keycaps.&lt;/p&gt;
&lt;p&gt;Being forced to remember is painful but recall helps you learn faster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Practice in small bursts.&lt;/p&gt;
&lt;p&gt;Small and frequent sessions are better than few but larger ones.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learn to touch type.&lt;/p&gt;
&lt;p&gt;Might as well learn it properly from the start.&lt;/p&gt;
&lt;p&gt;Note that you don’t have to be super strict.
I press the upper corners with my ring fingers instead of the pinky for instance (because I’m weird and it feels better).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you want to retain the ability to type QWERTY, use a different setup.&lt;/p&gt;
&lt;p&gt;A different keyboard for a different layout can help keep them separate.
Pressing space with a different thumb is another trick that may help.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are very good online tools to help you learn a layout.
Here are some I like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s important to stress how much motivation matters.
Even though I feel that I want to pick up the practice again when I’m writing this,
I don’t think that will actually happen as I’m not really motivated enough.
But if you start using a new layout you &lt;strong&gt;have&lt;/strong&gt; to practice, and you have to practice quite a lot at least at the beginning.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/monkey_sessions.png&quot;&gt;
&lt;figcaption&gt;My practice died off hard a year ago when I got good enough, around 70 wpm.&lt;br&gt;
(Some of this was spent practicing numbers and symbols.)
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;FAQ&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#FAQ&quot; class=&quot;heading-ref&quot;&gt;FAQ&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;You dodged the question; Was it worth it?&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hell yes it was.
The massive amount of nerd points alone is enough.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;I still want to use QWERTY on a regular keyboard&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you continue using it regularly you’ll be fine.
After 2 years I can still type faster with QWERTY on my laptop than with my own layout on my ergonomical keyboard, and I can use both an English and Swedish layout (symbols move around and &lt;code&gt;åäö&lt;/code&gt; are added).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;How long does it take to learn a new layout?&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Impossible to say as we’re all different.
The first layout I learned took ~16 hours of practice time on &lt;a href=&quot;https://www.keybr.com/&quot; title=&quot;Keybr: Typing practice&quot;&gt;keybr&lt;/a&gt; until I got up to ~40 wpm and with the second layout it took ~12 hours.
At ~40 wpm I felt I could write without wanting to throw the keyboard through the monitor.&lt;/p&gt;
&lt;p&gt;Beyond that it depends on how diligent you are with practice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Sounds like a massive effort, I don’t think it’s worth it?&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If this sounds too much for you, it probably is.&lt;/p&gt;
&lt;p&gt;I rationalized it by saying that I’ll spend a few decades more programming, so a big investment now will pay for itself with time as long as there’s some benefit.&lt;/p&gt;
&lt;p&gt;(This is indeed the trick on how to waste time on Very Productive™ things like &lt;a href=&quot;/blog/2023/10/01/rewriting_my_neovim_config_in_lua/&quot; title=&quot;Rewriting my Neovim config in Lua&quot;&gt;rewriting your Neovim setup&lt;/a&gt;.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
</content></entry><entry><title>The killer features of the Steam Deck</title><id>http://jonashietala.se/blog/2023/10/24/the_killer_features_of_the_steam_deck/index.html</id><updated>2024-07-01T05:28:09+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/24/the_killer_features_of_the_steam_deck" rel="alternate"/><published>2023-10-24T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;In the beginning of the year I gave myself a late Christmas gift and bought a &lt;a href=&quot;https://www.steamdeck.com/en/&quot;&gt;Steam Deck&lt;/a&gt; for myself.
There were two main reasons I decided to buy it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
I wanted my kids to play games instead of passively consuming endless amounts of YouTube.
&lt;/li&gt;
&lt;li&gt;
I wanted to combat my &lt;a href=&quot;/blog/2023/03/14/battling_burnout/&quot;&gt;burnout and depression&lt;/a&gt; by picking up gaming again.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And boy did it deliver.
The Deck is probably the most impressive thing I can remember buying since… I don’t know, maybe my first smartphone?&lt;/p&gt;
&lt;p&gt;I think it impresses me so much thanks to these five killer features:&lt;/p&gt;
&lt;section id=&quot;Killer-feature-1-Sleep-mode&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Killer-feature-1-Sleep-mode&quot; class=&quot;heading-ref&quot;&gt;Killer feature #1: Sleep mode&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For me, as a father of three where my gaming time is very limited and can be interrupted at any time, the one truly outstanding feature of the Deck is the sleep mode.&lt;/p&gt;
&lt;p&gt;It works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Press the sleep button, and the Deck will turn off in about a second.
&lt;/li&gt;
&lt;li&gt;
Press the sleep button again, and the Deck will turn on and resume exactly where you were, in a second.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This has worked perfectly for me for every game I’ve tried.
And it’s revolutionary.&lt;/p&gt;
&lt;p&gt;It’s no exaggeration to say that without this one feature, nothing else could’ve allowed me to find time to game.
The ability to instantly put it down and go to the screaming baby has been crucial,
and being able to instantly teleport myself back into an immersive gaming experience has been fantastic.&lt;/p&gt;
&lt;p&gt;If you’re a parent who wants to game, this is the feature you’ve been waiting for.
Even if you’re not a parent this is an amazing feature.&lt;/p&gt;
&lt;p&gt;If a portable gaming device doesn’t have this, don’t bother.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Killer-feature-2-The-steam-library&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Killer-feature-2-The-steam-library&quot; class=&quot;heading-ref&quot;&gt;Killer feature #2: The steam library&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The second feature I want to highlight is access to &lt;a href=&quot;https://store.steampowered.com/&quot;&gt;Steam&lt;/a&gt;.
It’s the largest distributor of PC games by a wide margin, and the amount of games available on the platform should be enough for anyone.&lt;/p&gt;
&lt;p&gt;And I must mention the Steam sales.
Many games are heavily discounted over the year, and you can even get AAA games for cheap if you’re patient enough.
Contrast this with Nintendo where the games are never on sale.&lt;/p&gt;
&lt;p&gt;To be sure, the Steam Deck is a handheld and won’t be able to run the most demanding games and it also runs Linux so it will have compatibility issues with a lot of games.
But the device is surprisingly powerful, and the work Valve has put in to make &lt;a href=&quot;https://www.protondb.com/&quot;&gt;Windows games work on Linux&lt;/a&gt; is astounding, so a lot of the games will work outright or with some minor tweaks (by changing the &lt;a href=&quot;https://www.protondb.com/&quot;&gt;Proton&lt;/a&gt; version or tweaking graphics settings).&lt;/p&gt;
&lt;p&gt;Just to give you a taste, here’s a variety of games that are installed on my Deck that all work great:&lt;/p&gt;
&lt;section id=&quot;LEGO-RPGs&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#LEGO-RPGs&quot; class=&quot;heading-ref&quot;&gt;LEGO RPGs&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/lego_city.jpg&quot;&gt;
&lt;figcaption&gt;LEGO City Undercover. It’s GTA but for kids!
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/steam_deck/star_wars.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/star_wars.jpg&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/steam_deck/jurassic_park.jpg&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/jurassic_park.jpg&quot;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;The LEGO games have been popular, although they’re a bit too difficult at times for my kids.
&lt;a href=&quot;https://store.steampowered.com/app/920210/LEGO_Star_Wars_The_Skywalker_Saga/&quot;&gt;LEGO Star Wars: The Skywalker Saga&lt;/a&gt;, &lt;a href=&quot;https://store.steampowered.com/app/352400/LEGO_Jurassic_World/&quot;&gt;LEGO Jurassic World&lt;/a&gt; and &lt;a href=&quot;https://store.steampowered.com/app/578330/LEGO_City_Undercover/&quot;&gt;LEGO City Undercover&lt;/a&gt; have all been very well received.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Overcooked-2&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Overcooked-2&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/728880/Overcooked_2/&quot;&gt;Overcooked! 2&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/overcooked2.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;As great as the LEGO games are, &lt;a href=&quot;https://store.steampowered.com/app/728880/Overcooked_2/&quot;&gt;Overcooked! 2&lt;/a&gt; is my favorite game for kids.
The beauty is how it forces you to collaborate with each other in a very nice way.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Forza-Horizon-5&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Forza-Horizon-5&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/1551360/Forza_Horizon_5/&quot;&gt;Forza Horizon 5&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/forza.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://store.steampowered.com/app/1551360/Forza_Horizon_5/&quot;&gt;Forza Horizon 5&lt;/a&gt; is another game that works great on the Deck.
It hasn’t been played as much as other games because it’s still a bit too difficult, even with driving assist.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Teenage-Mutant-Ninja-Turtles-Shredders-Revenge&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Teenage-Mutant-Ninja-Turtles-Shredders-Revenge&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/1361510/Teenage_Mutant_Ninja_Turtles_Shredders_Revenge/&quot;&gt;Teenage Mutant Ninja Turtles: Shredder’s Revenge&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/ninja_turtles.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I went with the boys to watch &lt;a href=&quot;https://www.imdb.com/title/tt8589698/&quot;&gt;Teenage Mutant Ninja Turtles: Mutant Mayhem&lt;/a&gt; on cinema.
They, and I, loved it.
&lt;a href=&quot;https://store.steampowered.com/app/1361510/Teenage_Mutant_Ninja_Turtles_Shredders_Revenge/&quot;&gt;Shredder’s Revenge&lt;/a&gt; has also been very well received, but alas, once again, it’s a little too difficult for my young kids.
Or should I say; they haven’t learned to handle defeat properly yet.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Faster-than-Light&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Faster-than-Light&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/212680/FTL_Faster_Than_Light/&quot;&gt;Faster than Light&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/ftl/stealth_b.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I rediscovered one of my favorite games of all time, and &lt;a href=&quot;/blog/2023/06/16/i_beat_ftl_on_hard_with_all_ships_in_the_game/&quot;&gt;spent 231 hours to beat it on hard with all the ships&lt;/a&gt;.
Make no mistake, this game is &lt;strong&gt;really hard&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Parkitect&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Parkitect&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/453090/Parkitect/&quot;&gt;Parkitect&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/parkitect.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://store.steampowered.com/app/453090/Parkitect/&quot;&gt;Parkitect&lt;/a&gt; is an ode to one of my favorite games of all time: &lt;a href=&quot;https://store.steampowered.com/app/285310/RollerCoaster_Tycoon_Deluxe/&quot;&gt;Rollercoaster Tycoon&lt;/a&gt;.
And I must admit, Parkitect is &lt;strong&gt;even better&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Grim-Dawn&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Grim-Dawn&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/219990/Grim_Dawn/&quot;&gt;Grim Dawn&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/grim_dawn.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;People were hyping on Diablo 4 so much.
Me being so over Blizzard, I instead played some &lt;a href=&quot;https://store.steampowered.com/app/219990/Grim_Dawn/&quot;&gt;Grim Dawn&lt;/a&gt;.
According to the internet it’s an objectively better game.
Regardless if that’s correct, the game does work very well on the Deck.&lt;/p&gt;
&lt;p&gt;(I actually haven’t played it that much—I didn’t enjoy the ARPG grind.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Tony-Hawks-Pro-Skater-1-2&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Tony-Hawks-Pro-Skater-1-2&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/2395210/Tony_Hawks_Pro_Skater_1__2/&quot;&gt;Tony Hawk’s Pro Skater 1 + 2&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/tony_hawk.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;I have very fond memories of playing &lt;a href=&quot;https://store.steampowered.com/app/2395210/Tony_Hawks_Pro_Skater_1__2/&quot;&gt;Tony Hawk&lt;/a&gt; games on the GameBoy Advance and on the PC.
I couldn’t help myself and had to relive those memories.&lt;/p&gt;
&lt;p&gt;And the game runs like a dream.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Killer-feature-3-Steam-input&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Killer-feature-3-Steam-input&quot; class=&quot;heading-ref&quot;&gt;Killer feature #3: Steam input&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may have noticed that I listed some games you wouldn’t think worked well on a handheld.
&lt;a href=&quot;https://store.steampowered.com/app/453090/Parkitect/&quot;&gt;Parkitect&lt;/a&gt; for instance heavily relies on the mouse, and &lt;a href=&quot;https://store.steampowered.com/app/212680/FTL_Faster_Than_Light/&quot;&gt;Faster than Light&lt;/a&gt; is a decade old game that’s also mouse based and doesn’t have an gamepad specific mappings.
What gives?&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://partner.steamgames.com/doc/features/steam_controller&quot;&gt;Steam Input&lt;/a&gt; the Deck allows you to remap any key or command to whatever input you want.
Combine that with the Deck’s excellent trackpads and you can comfortably play any game (well, maybe not RTS games or FPS games like Counter-Strike).&lt;/p&gt;
&lt;p&gt;As an example here’s my configuration for FTL:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/ftl_input.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Some notable features to mention:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Right trackpad as a mouse.
&lt;/li&gt;
&lt;li&gt;
Buttons for the most common utilities (doors, teleport, hacking, return to stations…).
&lt;/li&gt;
&lt;li&gt;
Sticks for number rows (weapon and drone selection) and &lt;code&gt;M&lt;/code&gt; for mindcontrol.
&lt;/li&gt;
&lt;li&gt;
Shift and control are relegated to back buttons.
&lt;/li&gt;
&lt;li&gt;
In FTL there are two pause buttons (space bar and mouse middle click). By pressing them quickly in succession you can &lt;a href=&quot;https://www.youtube.com/watch?v=C5RAHsrim-g&quot;&gt;micro pause&lt;/a&gt; and advance the game just a few frames. I’ve bound a single button on the Deck to do this, with a small delay between.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This may seem scary, but for most games you won’t need to change anything.
But when you do, &lt;a href=&quot;https://partner.steamgames.com/doc/features/steam_controller&quot;&gt;Steam Input&lt;/a&gt; is a godsend.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Killer-feature-4-An-open-platform&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Killer-feature-4-An-open-platform&quot; class=&quot;heading-ref&quot;&gt;Killer feature #4: An open platform&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What first got me excited about the Deck was actually that the Deck might represent the first big leap forwards in making Linux a valid gaming platform.
And thanks to &lt;a href=&quot;https://www.protondb.com/&quot;&gt;Proton&lt;/a&gt; I think that’s absolutely true, but the real value for the Steam Deck owner is that it’s an open platform and you can do what you want with it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Want to &lt;strong&gt;&lt;strong&gt;use other game stores&lt;/strong&gt;&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;Sure!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do you want to &lt;strong&gt;&lt;strong&gt;install native Linux games&lt;/strong&gt;&lt;/strong&gt; not on Steam, like &lt;a href=&quot;https://veloren.net/&quot;&gt;Veloren&lt;/a&gt; or &lt;a href=&quot;https://clonehero.net/&quot;&gt;Clone Hero&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;They work great!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Want to &lt;strong&gt;&lt;strong&gt;watch a movie&lt;/strong&gt;&lt;/strong&gt; instead of gaming?&lt;/p&gt;
&lt;p&gt;Launch desktop mode and it’s just a regular computer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don’t want to bring your laptop, but &lt;strong&gt;&lt;strong&gt;need to do some development&lt;/strong&gt;&lt;/strong&gt; on the go?&lt;/p&gt;
&lt;p&gt;Just setup your environment and go.
You can program using the virtual keyboard, but it sucks in a major way, so bring a keyboard.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/neovim.jpg&quot;&gt;
&lt;figcaption&gt;My Neovim config running on the Deck. See &lt;a href=&quot;https://blog.meinside.dev/How-to-Setup-Development-Environment-on-Steam-Deck/&quot;&gt;this post&lt;/a&gt; on how to install Neovim on the Steam Deck.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do you just want to &lt;strong&gt;&lt;strong&gt;install Windows&lt;/strong&gt;&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;Absolutely. Do you want to install it on the SD-card or on the Deck itself?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m a strong believer in that you should be allowed to do whatever you want with your device, and with the Steam Deck you can.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Killer-feature-5-Emulation&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Killer-feature-5-Emulation&quot; class=&quot;heading-ref&quot;&gt;Killer feature #5: Emulation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The last feature I want to bring up ties into the previous: the Steam Deck is an amazing platform for emulation.&lt;/p&gt;
&lt;p&gt;I’m new to emulation, but it was very easy to setup using &lt;a href=&quot;https://www.emudeck.com/&quot;&gt;EmuDeck&lt;/a&gt;.
The device itself is powerful enough to run basically any older game, and even many popular Switch games.&lt;/p&gt;
&lt;p&gt;You may ask, if Steam already has tons of games, why bother with emulation?&lt;/p&gt;
&lt;p&gt;I’ve got a few reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Many good games aren’t on Steam (Nintendo, I’m looking at you).
&lt;/li&gt;
&lt;li&gt;
Nostalgia.
&lt;/li&gt;
&lt;li&gt;
Experience the classics.
&lt;/li&gt;
&lt;li&gt;
Some gaming experiences aren’t replicated well by the newer styles of games.
&lt;/li&gt;
&lt;li&gt;
If you look at the many “best games of all time” lists out there (which I did when I asked myself what have I been missing out on during my years of not gaming) you’ll find that a lot of them are from older systems.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, maybe you’ve heard of &lt;strong&gt;&lt;strong&gt;The Legend of Zelda&lt;/strong&gt;&lt;/strong&gt;?
I have, but I’ve only ever played a single game (Link’s Awakening).
This is super unfortunate because some of the Zelda games are rated as the best games in history.&lt;/p&gt;
&lt;p&gt;But if you want to play through the Zelda series you’d have to collect almost every Nintendo console.&lt;/p&gt;
&lt;p&gt;Or you can play &lt;strong&gt;the whole series&lt;/strong&gt;, including the newest Switch games, on the Deck.&lt;/p&gt;
&lt;p&gt;I admit this is a contrived example because I haven’t done this yet (I plan to play through the most popular ones at some point), so here’s a list of games that we’ve actually played:&lt;/p&gt;
&lt;section id=&quot;Mario-Kart-8-Deluxe&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Mario-Kart-8-Deluxe&quot; class=&quot;heading-ref&quot;&gt;Mario Kart 8 Deluxe&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/mario_kart.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Both of my boys (6 and 3 years) love Mario Kart.
The best feature is probably the driving assist, so the younger kid can play even if all he does is press the jump button and shout.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Super-Smash-Bros&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Super-Smash-Bros&quot; class=&quot;heading-ref&quot;&gt;Super Smash Bros&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/smash.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Mario Kart has been our most played game, but it’s quickly being overtaken by Super Smash Bros that my older boy has been playing non-stop for weeks now.&lt;/p&gt;
&lt;p&gt;But I understand him, it’s an awesome game and it was my favorite Nintendo game when growing up.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Pokémon-Snap&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Pokémon-Snap&quot; class=&quot;heading-ref&quot;&gt;Pokémon Snap&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/snap.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;My oldest is in a Pokémon craze at the moment.
Since he hasn’t learned to read yet the “real” Pokémon games are a bit too much to play by himself, but taking pictures of Pokémon works very well.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Punch-Out&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Punch-Out&quot; class=&quot;heading-ref&quot;&gt;Punch Out&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/punch_out.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Punch Out is pure nostalgia for me.
Amazing.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Pokémon-Unbound&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Pokémon-Unbound&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://www.pokemoncoders.com/pokemon-unbound/&quot;&gt;Pokémon Unbound&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/steam_deck/unbound.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Speaking of nostalgia, of course I need to mention Pokémon.
I had difficulty deciding what Pokémon game to play—there are a few—and then I just happened to discover the rabbit hole of Pokémon ROM hacks.&lt;/p&gt;
&lt;p&gt;According to my pre-study &lt;a href=&quot;https://www.pokemoncoders.com/pokemon-unbound/&quot;&gt;Pokémon Unbound&lt;/a&gt; is the best ROM hack there is, so that’s where I started.
But there’s &lt;strong&gt;a lot&lt;/strong&gt; here to explore.
Maybe I’ll get there eventually.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Isnt-there-more-to-the-Steam-Deck&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Isnt-there-more-to-the-Steam-Deck&quot; class=&quot;heading-ref&quot;&gt;Isn’t there more to the Steam Deck?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s absolutely more to like about the Deck. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
It’s a handheld you can dock.
&lt;/li&gt;
&lt;li&gt;
The processor is very capable given the amount of power it uses.
&lt;/li&gt;
&lt;li&gt;
You can connect a lot of things to it; controllers, fight sticks, Wii guitars etc.
&lt;/li&gt;
&lt;li&gt;
The trackpads are very good as a mouse replacement.
&lt;/li&gt;
&lt;li&gt;
The year of Linux has finally arrived!
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While nice, they don’t quite qualify for my killer features list.
And most importantly: I wanted to keep it simple and only select five killer features.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Bed &amp; electronics</title><id>http://jonashietala.se/blog/2023/10/22/lets_build_a_voron_bed_electronics/index.html</id><updated>2026-01-29T10:45:17+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/22/lets_build_a_voron_bed_electronics" rel="alternate"/><published>2023-10-22T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve made a lot of progress on my VORON.
Electronics and other stuff are installed to the degree that I’ve begun wiring, but I’m going to separate the wiring into it’s own post.&lt;/p&gt;
&lt;p&gt;This will be a short post about bed preparation and installing electronics components.&lt;/p&gt;
&lt;h1&gt;Feedback from the VORON forum&lt;/h1&gt;
&lt;p&gt;I’ve gotten &lt;a href=&quot;https://forum.vorondesign.com/threads/ldo-trident-250-complete-3d-printer-beginner.1089/&quot;&gt;some feedback&lt;/a&gt; from the friendly VORON forum on some issues I should take a look at:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Verify that the frame is built square (I’ve tried to do so).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The front Z motor mounts were swapped.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/rotated_front_pieces.jpg&quot; /&gt;
&lt;figcaption&gt;Front Z motor mounts now have the VORON logo at the front.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I should &lt;a href=&quot;https://www.youtube.com/watch?v=cOn6u9kXvy0&amp;amp;embeds_referring_euri=https%3A%2F%2Fforum.vorondesign.com%2F&amp;amp;source_ve_path=OTY3MTQ&amp;amp;feature=emb_imp_woyt&quot;&gt;check the gantry racking&lt;/a&gt; to get rid of it catching (I haven’t done that yet, I want to finish up the wiring first).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Misaligned extrusion&lt;/h1&gt;
&lt;p&gt;When I was going to insert the top cover I noticed that the Z motor didn’t fit into the cutout, and I discovered that the center extrusion wasn’t right in the middle:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/plate_dosent_fit.jpg&quot;&gt;&lt;img src=&quot;/images/trident/plate_dosent_fit.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/screw_is_misaligned.jpg&quot;&gt;&lt;img src=&quot;/images/trident/screw_is_misaligned.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I have a small memory that I measured it, and the spacing was off by a little, but then maybe I forgot to do something about it?
Just goes to show how my plans of taking the build slowly and trying to be thorough doesn’t prevent me from doing silly mistakes.&lt;/p&gt;
&lt;h1&gt;The buildplate&lt;/h1&gt;
&lt;p&gt;Even though the assembly manual says that you should install the buildplate at this point, I decided to skip it.
I got the tip from Nero3D to only install it at the very end, even after wiring, because it’s heavy and makes the printer more annoying to flip around during the build.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/annoying_screws.jpg&quot; /&gt;
&lt;figcaption&gt;These screws were extremely hard to screw down… Maybe I need better tools?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Other than the small screws murdering my fingers, installing the final extrusions was straightforward.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/t_extrusions.jpg&quot;&gt;&lt;img src=&quot;/images/trident/t_extrusions.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/buildplate.jpg&quot;&gt;&lt;img src=&quot;/images/trident/buildplate.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/mount_installed.jpg&quot; /&gt;
&lt;figcaption&gt;Bed mount installed.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Electronics&lt;/h1&gt;
&lt;p&gt;And now the part of the build I’ve been most worried about begins; avoiding blowing up the electronic components.&lt;/p&gt;
&lt;p&gt;Well, that requires wiring so maybe I’ll blow it up in the next post.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/rails.jpg&quot;&gt;&lt;img src=&quot;/images/trident/rails.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/jumpers.jpg&quot;&gt;&lt;img src=&quot;/images/trident/jumpers.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I couldn’t find the &lt;a href=&quot;https://github.com/MotorDynamicsLab/LDOVoron2/blob/main/STLs/beefy_raspberry_bracket.stl&quot;&gt;LDO Beefy Raspberry Pi Mount&lt;/a&gt; in my printed parts.
But why would I need it, the standard parts work well?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/elecronics_placed.jpg&quot; /&gt;
&lt;figcaption&gt;The big electronic components are laid out.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Again, laying out the components were no big deal.
Embarrassingly, the most trouble I had was locating the microSD slot for the Raspberry Pi (it’s underneath).&lt;/p&gt;
&lt;p&gt;Next up is the dreaded wiring.&lt;/p&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Toolhead</title><id>http://jonashietala.se/blog/2023/10/18/lets_build_a_voron_toolhead/index.html</id><updated>2026-01-29T10:44:55+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/18/lets_build_a_voron_toolhead" rel="alternate"/><published>2023-10-18T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Since the last update I’ve made some good progress:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All the motors are installed&lt;/li&gt;
&lt;li&gt;The x-axis and belt are installed&lt;/li&gt;
&lt;li&gt;Tap is installed&lt;/li&gt;
&lt;li&gt;The toolhead with Stealthburner + Clockwork 2 is also installed&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/front_p2.jpg&quot; /&gt;
&lt;figcaption&gt;Purple means Pretty.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve run into a few problems on the way that I’ll try to document, but other than that the build has been really fun so far.
The design of Clockwork, Stealthburner and Core XY is really cool and it’s been very interesting to assemble them to see how it all comes together.&lt;/p&gt;
&lt;h1&gt;X-axis and belts&lt;/h1&gt;
&lt;p&gt;I didn’t encounter any issue assembling the x-axis or the belts.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/x_axis.jpg&quot; /&gt;
&lt;/figure&gt;&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/trident/belts.jpg&quot;&gt;&lt;img src=&quot;/images/trident/belts.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trident/belts_back.jpg&quot;&gt;&lt;img src=&quot;/images/trident/belts_back.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I’m slightly worried that I messed something up as moving the gantry from front to back has a very slight hiccup in the middle, but it doesn’t come up when I move it from back to front or if I move it slowly.&lt;/p&gt;
&lt;h1&gt;Toolhead&lt;/h1&gt;
&lt;p&gt;Up to here it’s been fairly straightforward.
Just follow the &lt;a href=&quot;https://raw.githubusercontent.com/VoronDesign/Voron-Trident/main/Manual/Assembly_Manual_Trident.pdf&quot;&gt;official assembly guide&lt;/a&gt; and don’t forget to read the &lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron-trident/build-faq&quot;&gt;LDO Build Notes/FAQ&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But assembling the toolhead (or printhead, what’s the difference?) was not so simple and I had to reference several sources:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap/blob/main/Manual/Assembly_Manual_Tap.pdf&quot;&gt;VORON Tap manual&lt;/a&gt; and &lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap/blob/main/Manual/R8_errata.md&quot;&gt;VORON Tap errata&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/VoronDesign/Voron-Stealthburner/blob/main/Manual/Assembly_Manual_SB.pdf&quot;&gt;VORON Stealthburner manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ldomotion.com/p/guide/18295873486194241&quot;&gt;LDO Voron Stealthburner + Clockwork 2 + LDO Toolhead PCB Revised&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron-trident/wiring_guide_250_rev_a&quot;&gt;LDO Voron Trident 250 Wiring Guide (Rev. A/C)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ldomotors.com/adxl_tool&quot;&gt;LDO Input Shaper Toolkit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ST6RsnRVsTI&quot;&gt;VORON 2.4 R2 MPX CBT build series part 16 - Rapido HF hot end unbox and installation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This was confusing and I managed to trip up on several things.&lt;/p&gt;
&lt;h2&gt;Tap&lt;/h2&gt;
&lt;p&gt;My plan wasn’t actually to build Tap from the start, and instead rely on the standard inductive probe.
Even though &lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron-trident&quot;&gt;the kit stated&lt;/a&gt; the probe was included, it wasn’t listed in the parts checklist so I assume it wasn’t included in the kit?&lt;/p&gt;
&lt;aside&gt;I later found it in a bag in the cable box.&lt;/aside&gt;
&lt;p&gt;No big deal.
Instead of building the Klicky probe just to tear it down and replace with Tap later, I decided to build Tap from the get-go.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/tap_parts.jpg&quot; /&gt;
&lt;figcaption&gt;Tap in progress.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The first thing that confused me was the printed parts.
In &lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap/blob/main/Manual/Assembly_Manual_Tap.pdf&quot;&gt;the Tap manual&lt;/a&gt; the main printed part had the VORON logo, yet my part did not.
There were some other minor differences, so maybe I got the printed parts from an older revision of Tap?&lt;/p&gt;
&lt;p&gt;But &lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap/blob/main/Manual/Assembly_Manual_Tap.pdf&quot;&gt;the manual&lt;/a&gt; also didn’t seem updated to the latest version as it was &lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap/blob/main/Manual/R8_errata.md&quot;&gt;missing items from the errata&lt;/a&gt; (which I only discovered after assembling Tap).
There were no mentions of the tall reinforcement screws (that I could install afterwards), belt covers (that I didn’t use) or how to install the 2 extra magnets (that now lie unused).&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/tap_unused_parts.jpg&quot; /&gt;
&lt;figcaption&gt;I got the &lt;a href=&quot;https://lab4450.com/product/voron-tap-probe/&quot;&gt;Hardware Kit + OptoTap rev2.4.1 5v or 24v OPB666N HIGH TEMP + D2HW&lt;/a&gt; “kitchen sink” kit, but the amount of unused parts worries me.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Still, I got it assembled and it seems to work? &lt;em&gt;Crosses fingers.&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/tap_mounted.jpg&quot; /&gt;
&lt;figcaption&gt;Tap is mounted and ready to go.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Clockwork, mod or no mod?&lt;/h2&gt;
&lt;p&gt;For the top part of the Stealthburner, I did the component prep and then I noticed that the LDO documentation refers to &lt;a href=&quot;https://www.ldomotion.com/p/guide/18295873486194241&quot;&gt;a revision&lt;/a&gt; that called for using alternative printed parts.&lt;/p&gt;
&lt;p&gt;Okay, okay.
I redid installed heatset inserts on those parts as well and went to work.
It went well until I had to install the PCB and the printed mount (from the revision) didn’t fit.&lt;/p&gt;
&lt;p&gt;Alright, improvisation time:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/heatset_standoff.jpg&quot; /&gt;
&lt;figcaption&gt;I didn’t find how to attach the PCB in the documentation, so I improvised with heatset inserts. I feel so clever!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Of course later on I found a plastic part that was made for the job and replaced the mount:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/plastic_standoff.jpg&quot; /&gt;
&lt;figcaption&gt;This is how the PCB is supposed to be mounted.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;… And then I found out why it didn’t fit. There was this line &lt;a href=&quot;https://www.ldomotion.com/p/guide/18295873486194241&quot;&gt;in the revision&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;THIS MOD NO LONGER REQUIRED for V2.4 Rev. C - the kit includes the Stealthburner PCBs and works with the stock parts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’m not building a V2.4, so I didn’t think it applied to me.
But now I think it was a bad assumption.
I’m building the Rev.C of the Trident, which seems to have the new version of the PCB that fits the standard parts.&lt;/p&gt;
&lt;p&gt;At first I was going to leave it like this cause why bother, but then I read &lt;a href=&quot;https://docs.ldomotors.com/en/voron/voron-trident/wiring_guide_250_rev_a&quot;&gt;a note hidden in the wiring guide&lt;/a&gt; that for the new PCB I needed to use a &lt;a href=&quot;https://github.com/VoronDesign/Voron-Hardware/blob/master/Stealthburner_Toolhead_PCB/STLs/cable_cover_pcb_with_thermistor.stl&quot;&gt;specific cable cover&lt;/a&gt; that of course wasn’t compatible with the modified parts…&lt;/p&gt;
&lt;p&gt;So I redid everything.&lt;/p&gt;
&lt;p&gt;And then I discovered that the &lt;a href=&quot;https://github.com/VoronDesign/Voron-Hardware/blob/master/Stealthburner_Toolhead_PCB/STLs/cable_cover_pcb_with_thermistor.stl&quot;&gt;specific cable cover&lt;/a&gt; I had was missing the thermistor holder:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/missing_thermistor_holder.png&quot; /&gt;
&lt;figcaption&gt;My printed part doesn’t have this holder.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Darn it.&lt;/p&gt;
&lt;p&gt;But I think (hope) it should finally be finished enough; I can probably tuck the thermistor somewhere to get it to print.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/clockwork.jpg&quot; /&gt;
&lt;figcaption&gt;Now I think it’s built as it should be?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Installing a hotend&lt;/h2&gt;
&lt;p&gt;When I was going to install the Rapido UHF hotend that I got I had a small panic.&lt;/p&gt;
&lt;p&gt;I couldn’t find any VORON documentation on how to install it (the assembly manual only shows another hotend).
From Rapido I got a very nice looking card pointing to &lt;a href=&quot;https://www.phaetus.com/rapido-hotend&quot;&gt;https://www.phaetus.com/rapido-hotend&lt;/a&gt; that led nowhere.&lt;/p&gt;
&lt;p&gt;And when I tried searching for it online I found that Rapido UHF actually wasn’t supported!&lt;/p&gt;
&lt;p&gt;Oh no!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/rapido_how_to_fit.jpg&quot; /&gt;
&lt;figcaption&gt;No matter how I look at it, this won’t fit? How are you even supposed to attach it? It does say P-RPD but I don’t understand…&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I was sure I read that the UHF version also contained HF parts, but maybe that was wrong?
Do I need to buy new printed parts from someone?
Or maybe a new hotend?
Buy the Rapido HF instead of the UHF I got?&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I’m off watching reviews on the newly released Rapido 2.0…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Luckily I found &lt;a href=&quot;https://www.youtube.com/watch?v=ST6RsnRVsTI&quot;&gt;a YouTube video showing how to install it&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/rapido_fits.jpg&quot; /&gt;
&lt;figcaption&gt;Oooh, you just remove the top part (and don’t install the UHF parts) and it fits!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Crisis averted; all is well.&lt;/p&gt;
&lt;h2&gt;Stealthburner assembly&lt;/h2&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/sb_cover.jpg&quot; /&gt;
&lt;figcaption&gt;Before connecting it all.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It was slightly scary that you had to break off and cut into a fan—I really didn’t want to mess it up permanently.
But after watching &lt;a href=&quot;https://www.youtube.com/live/MQ5_LHwR4n4?si=hEcvBxwaGwO-Tjeg&amp;amp;t=9882&quot;&gt;NERO 3D&lt;/a&gt; do that I managed to collect the courage to do it as well.&lt;/p&gt;
&lt;p&gt;When I was going to plug in the hotend I noticed it didn’t connect to the PCB properly:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/hotend_connector_mismatch.jpg&quot; /&gt;
&lt;figcaption&gt;Nope, the cable doesn’t go into that connector.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Tap also didn’t have a cable I could just use, so now I had to mess with the wires.
Tough luck, I didn’t have any 2-pin or 3-pin connectors (or extra cable), so I left this until later.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;That’s a future me problem. Screw that guy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Missing some minor parts&lt;/h1&gt;
&lt;p&gt;At this point I discovered I’m missing a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/VoronDesign/Voron-Stealthburner/blob/main/STLs/Stealthburner/ADXL345_Mounts/sb_adxl_mount_ldo_15mm_c_c.stl&quot;&gt;Printed part&lt;/a&gt; for the input shaper.&lt;/p&gt;
&lt;p&gt;Maybe I just haven’t found it, but either way it’s not a big deal.
Input shaper seems to be a temporary thing that you should remove after some calibration,
so I guess I can just tape it temporarily.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The LDO &lt;a href=&quot;https://github.com/VoronDesign/Voron-Hardware/blob/master/Stealthburner_Toolhead_PCB/STLs/cable_cover_pcb_with_thermistor.stl&quot;&gt;specific cable cover&lt;/a&gt; I mentioned before.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2 Locking Washer, M5&lt;/p&gt;
&lt;p&gt;Maybe I can find two of these things in the hardware store somewhere?
Ordering these online for only two pieces seems like a hassle.&lt;/p&gt;
&lt;p&gt;I’ve contacted 3Djake about the washers, maybe they’ll find some replacement parts for me.
But even if they don’t it’s no big deal.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I thought I was missing the neopixels and the inductive probe, but they were hiding in a bag in the cable box.&lt;/p&gt;
&lt;h1&gt;How does it feel?&lt;/h1&gt;
&lt;p&gt;Even though I’ve had a fair amount of trouble sorting through documentation and other issues, the progress has felt good.
It’s really fascinating to assemble things like the belt system and the toolhead and see how they come together.&lt;/p&gt;
</content></entry><entry><title>Let&apos;s build a VORON: Build start</title><id>http://jonashietala.se/blog/2023/10/13/lets_build_a_voron_build_start/index.html</id><updated>2026-01-29T10:45:40+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/13/lets_build_a_voron_build_start" rel="alternate"/><published>2023-10-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;
&lt;img src=&quot;/images/trident/trident.png&quot; /&gt;
&lt;figcaption&gt;The end goal, as rendered by Autodesk’s online viewer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’m not sure where it came from, but it was suddenly very important that I got myself a 3D printer.
Maybe it was an important insight, but it maybe it was only a fix idea I got that somehow became this all-import thing.&lt;/p&gt;
&lt;p&gt;Either way, I now have lots of parts for a &lt;a href=&quot;https://vorondesign.com/voron_trident&quot; title=&quot;VORON Trident 3D printer&quot;&gt;VORON Trident 250&lt;/a&gt; and I figured I’ll try to document the journey of building it (or failing to).&lt;/p&gt;
&lt;h1&gt;Why a VORON?&lt;/h1&gt;
&lt;p&gt;The first step to building a 3D printer is deciding on what printer to build.
This was roughly my selection process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An &lt;a href=&quot;https://www.creality.com/products/ender-3-3d-printer&quot; title=&quot;Ender 3 3D printer&quot;&gt;Ender 3&lt;/a&gt; seems like a cheap and popular printer, maybe that’s a good place to start?&lt;/li&gt;
&lt;li&gt;Hmm, the quality of an &lt;a href=&quot;https://www.creality.com/products/ender-3-3d-printer&quot; title=&quot;Ender 3 3D printer&quot;&gt;Ender 3&lt;/a&gt; doesn’t seem that great and the internet says that you’ll spend a lot of time to tweak and modify it until you get something good.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.prusa3d.com/en/product/original-prusa-mk4-2/&quot; title=&quot;Original Prusa MK4 3D printer&quot;&gt;Prusa MK4&lt;/a&gt; has just released, and their printers have historically been really solid.&lt;/li&gt;
&lt;li&gt;Prusa seems open-source friendly (well, sort-of) but I’d probably want an enclosure as well…&lt;/li&gt;
&lt;li&gt;There is a Prusa enclosure, but holy crap it’s large and expensive. Maybe there’s something else that has a built-in enclosure?&lt;/li&gt;
&lt;li&gt;Damn, this &lt;a href=&quot;https://vorondesign.com/&quot; title=&quot;VORON Design&quot;&gt;VORON&lt;/a&gt; thing looks amazing and at around the same price range of the Prusa.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that’s how I ended up wanting a &lt;a href=&quot;https://vorondesign.com/&quot; title=&quot;VORON Design&quot;&gt;VORON&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, a &lt;a href=&quot;https://vorondesign.com/&quot; title=&quot;VORON Design&quot;&gt;VORON&lt;/a&gt; is a really cool printer and there are lots of things that drew me towards it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It’s completely open source.&lt;/li&gt;
&lt;li&gt;The footprint is small and it comes with an enclosure.&lt;/li&gt;
&lt;li&gt;You can mod it to your hearts content.&lt;/li&gt;
&lt;li&gt;You build it from scratch, meaning you’ll get the knowledge of how to mod and repair it (I hope).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point it didn’t matter that I’m a complete 3D printer noob and that a &lt;a href=&quot;https://vorondesign.com/&quot; title=&quot;VORON Design&quot;&gt;VORON&lt;/a&gt; is not recommended for beginners.
I wanted one, and settling for something else would just leave me filled with regrets and I would’ve just bought a &lt;a href=&quot;https://vorondesign.com/&quot; title=&quot;VORON Design&quot;&gt;VORON&lt;/a&gt; later anyway.
So I bought the printer I wanted directly instead.&lt;/p&gt;
&lt;p&gt;I got the 250mm version over the 300 and the 350 simply because it’s much easier to fit in my office and in my storage.
I’m not planning to make any larger prints so the larger sizes felt unnecessary to me.&lt;/p&gt;
&lt;p&gt;Now as I said a &lt;a href=&quot;https://vorondesign.com/&quot; title=&quot;VORON Design&quot;&gt;VORON&lt;/a&gt; isn’t a beginner printer, but I did take some countermeasures to hopefully make the build more manageable for me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I Bought the expensive LDO kit as it’s as close to a “just build it” kit you can find.&lt;/li&gt;
&lt;li&gt;I went with the Trident over a 2.4 because the Trident is supposedly a little easier to build.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I also made one choice that probably makes it a little more difficult for myself:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Even though the kit comes with the Klicky Mod, I want to use &lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap&quot; title=&quot;VORON Tap&quot;&gt;VORON Tap&lt;/a&gt; because I got this idea that Tap would be better.&lt;/p&gt;
&lt;p&gt;At the moment I’m not planning to install Klicky at all, but we’ll see how that goes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As I don’t have a printer I used the &lt;a href=&quot;https://pif.voron.dev/&quot; title=&quot;VORON print it forward&quot;&gt;print it forward&lt;/a&gt; service to buy the printed parts for the printer.&lt;/p&gt;
&lt;h1&gt;What I got&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/boxes.jpg&quot; /&gt;
&lt;figcaption&gt;I’ve got a bunch of boxes&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;These are the items I’ve ordered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LDO VORON Trident 250&lt;/li&gt;
&lt;li&gt;Phaetus Rapido Plus Hotend UHF&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/VoronDesign/Voron-Tap&quot; title=&quot;VORON Tap&quot;&gt;VORON Tap hardware kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Printed parts&lt;/li&gt;
&lt;/ul&gt;
&lt;aside&gt;&lt;p&gt;I first ordered a kit from &lt;a href=&quot;https://caribou3d.com/en/&quot;&gt;caribou3d.com&lt;/a&gt; but after waiting months without progress I canceled it
and ordered from &lt;a href=&quot;https://www.3djake.com/&quot;&gt;3djake.com&lt;/a&gt; instead (where I bought the Rapido).&lt;/p&gt;
&lt;p&gt;But when I tried to cancel the order from caribou3d they told me they couldn’t make a
refund as they had to declare insolvency.
I did get a refund via PayPal, but I still strongly recommend you to &lt;strong&gt;avoid caribou3d&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h1&gt;Preloading the t-nuts&lt;/h1&gt;
&lt;p&gt;Assembling the frame wasn’t too bad.
I took it easy to make sure I put the extrusions the right place, rotated as they should be.&lt;/p&gt;
&lt;p&gt;But my big worry—that still isn’t resolved—is the preloading of the t-nuts.
Apparently LDO’s combination of nuts and extrusions is very tight and you can’t (or it’s super difficult) to insert them after assembling the frame, so you have to insert them before.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=hpkN9NHoKiY&quot; title=&quot;Preloading T-nuts&quot;&gt;There is a helpful video&lt;/a&gt;, but I’m still very worried that I’ve placed one of them wrong or missed some, and I have to disassemble the frame at a later stage.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/build_1.jpg&quot; /&gt;
&lt;figcaption&gt;Assembling the frame. I really, really hope that I’ve placed the t-nuts correctly.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Heatset inserts&lt;/h1&gt;
&lt;p&gt;What to do with the heatset inserts?
The LDO kit comes with a &lt;a href=&quot;https://docs.ldomotors.com/guides/heatset_insert_tool_guide&quot; title=&quot;Heatset tool insert guide&quot;&gt;heatset insert tool&lt;/a&gt;…
But it didn’t fit the soldering iron I had. What to do?&lt;/p&gt;
&lt;p&gt;Turns out you don’t need it, and you can just use the soldering iron with a regular tip:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/heatset_insert.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;This works great.
Except that I shouldn’t use this particular part in the build. Oops.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Set screws&lt;/h1&gt;
&lt;p&gt;Another source of great worry for me was this line in assembly manual:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Loose set screws account for the majority of issues that our users report.
Save yourself hours of troubleshooting and apply thread locker to all set screws during the build.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And I don’t even know what a “thread locker” is.&lt;/p&gt;
&lt;p&gt;After some research time it seems I really do want a thread locker, but I live in a really small community and I don’t know where to buy this (except ordering online and waiting for a week).&lt;/p&gt;
&lt;p&gt;Well maybe nail polish works just as well? So armed to the teeth with fire red &lt;del&gt;lipstick&lt;/del&gt; polish I was ready to tackle the problem…&lt;/p&gt;
&lt;p&gt;And I see that thread locker has been pre-applied to the set screws.
Maybe it will pay off with the more expensive kit after all?&lt;/p&gt;
&lt;h1&gt;Greasing the rails&lt;/h1&gt;
&lt;p&gt;Greasing the rails is another thing that bothered me, because grease (and cleaning) wasn’t found in the kits I bought.
My partners little brother came to the rescue and found a NLGI 1 grease (as recommended by the LDO guide) and some break cleaner to clean the rails.&lt;/p&gt;
&lt;p&gt;That’s great, but I also don’t have a syringe so I ended up removing the carriage and applying grease that way.
To my surprise they were full of small balls that had a tendency to jump out at me.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/tiny_balls.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;The balls jumped out on me. I hope I found them all?
(No, I later found some missing balls…)&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;At first I applied a bunch of grease on the balls as well, but then carriage moved really slowly over the rails, so in the end I applied a little grease only in the middle.&lt;/p&gt;
&lt;p&gt;They still don’t move as smoothly as they did when I opened the boxes, I hope it’ll be okay…&lt;/p&gt;
&lt;h1&gt;Best part of the build so far&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/build_loke.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;This is Loke’s hand.
I don’t want to publish pictures of my kids, so this is what you get.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So far the best part has been that both of my boys (5 and 3 years) have been helping me out, and they’ve been really enjoying being there and helping me tighten some screws.&lt;/p&gt;
&lt;p&gt;I really want all my kids to build and be creative.
Be it LEGO, sand castles, programming or 3D printers.
So far this project has been promising, and at least the older one is super hyped about the prospect of building his own Nerf guns.
I also want to build some toy robots and—when they get older—maybe a Quadcopter or two.&lt;/p&gt;
&lt;h1&gt;Where I’m at right now&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trident/build_2.jpg&quot; /&gt;
&lt;figcaption&gt;The frame is built and I’ve added three of the rails.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve had the printer for almost one month and progress has felt slow.&lt;/p&gt;
</content></entry><entry><title>Computer upgrade</title><id>http://jonashietala.se/blog/2023/10/09/computer_upgrade/index.html</id><updated>2023-10-09T18:04:30+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/09/computer_upgrade" rel="alternate"/><published>2023-10-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After 5 years or so I’ve made a large upgrade to my desktop, and this post contains details and some pictures about the process.&lt;/p&gt;
&lt;h1&gt;It was time&lt;/h1&gt;
&lt;p&gt;I didn’t really want to do an upgrade right now, but I felt I had to do it.
Sometimes the lag had gotten very noticeable, for example when running multiple Neovim instances with several different LSPs in Rust and Elixir.&lt;/p&gt;
&lt;p&gt;That was frustrating, but the biggest reason was this ghastly discovery in my liquid cooling loop:&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/computer_upgrade/disgusting.jpg&quot;&gt;&lt;img src=&quot;/images/computer_upgrade/disgusting.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/computer_upgrade/disgusting2.jpg&quot;&gt;&lt;img src=&quot;/images/computer_upgrade/disgusting2.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;If you can’t spot it (no shame on you), there’s a huge ball of gunk that’s stuck hanging down beneath the graphics card, and it almost seems like it’s blocking the liquid from passing through properly (more on that later).&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;know&lt;/em&gt; that you’re supposed to check on your loop once a year or so.
But things just sort of happened.
We moved, I worked and we got three kids.
Sometimes it’s just hard to take time for these things, but now I just had to do it or I might not have a computer left to work on.&lt;/p&gt;
&lt;h1&gt;The new things&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: AMD Ryzen 9 7950X&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;: Kingston 32GB DDR5 5200MHz CL40 FURY&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Motherboard&lt;/strong&gt;: ASRock B650 PG Lightning&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fans&lt;/strong&gt;: 8x Noctua NF-A14 PWM 140mm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSD&lt;/strong&gt;: Kingston KC3000 M.2 2280 NVMe SSD 2TB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Water cooling&lt;/strong&gt;: New tubing, fitting, a large reservoir and probably something more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Taking apart the computer is a pain, so I decided to do an upgrade as well.
I landed on a Ryzen 9 7950X, a beast of a CPU that should leave me with no slowness complaints (well, as few as possible I guess).
With that I also had to get a new motherboard and new DDR5 RAM memory.&lt;/p&gt;
&lt;p&gt;The fans were some gravy as some of the old fans occasionally stopped spinning and the SSD was just an impulse buy (it was big, fast and cheap).&lt;/p&gt;
&lt;p&gt;I redid the water cooling loop a little as well.
The position of the reservoir/pump combo wasn’t good and I wanted to try to get a position for better airflow.&lt;/p&gt;
&lt;h1&gt;Tearing down the loop&lt;/h1&gt;
&lt;p&gt;Building the liquid cooling loop was all fun and game 5 years ago, but now it was time to pay.
I had installed a drain, but it failed to drain most of the liquid.
There was something in the tube that blocked it, and the drain was mounted too high so it couldn’t drain the lower radiator properly.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/empty.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;Come on little disgusting thing, I know you want to come out.&lt;br /&gt;
I failed to drain most of the liquid trough the drain, so things got messy.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Why couldn’t I be satisfied with air cooling?&lt;/p&gt;
&lt;h1&gt;Rebuilding the loop&lt;/h1&gt;
&lt;p&gt;Building a computer isn’t hard, but adding in a custom loop makes the build take twice or thrice as long.&lt;/p&gt;
&lt;p&gt;But to be completely honest, it’s also a little fun.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/cleaning.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;I used &lt;a href=&quot;https://www.ekwb.com/shop/ek-cryofuel-loop-cleaner-superflush-concentrate-250ml&quot;&gt;loop cleaner + superflush&lt;/a&gt; to properly clean the system.
Because of the previous gunk, I was worried about dirt in the GPU block, the pump and radiators.
It’s hard to be sure, but I think I got rid of most of it.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/drain.jpg&quot; /&gt;
&lt;figcaption&gt;I was a good boy and added a fill valve to easily fill the loop.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/red_view.jpg&quot; /&gt;
&lt;figcaption&gt;How the valve connects to the reservoir.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I liked the idea the valve, but the first time I tried to fill up using it the liquid didn’t enter the reservoir properly and things got really messy.&lt;/p&gt;
&lt;p&gt;At first I thought that the tube had an U-bend in it, but what ultimately fixed it was me replacing the reservoir top so I could open up an air intake.&lt;/p&gt;
&lt;h1&gt;It’s… Not perfect&lt;/h1&gt;
&lt;p&gt;Despite my best efforts of planning the loop, the drain system ended up sucking.
While I managed to drain most of the liquid, there were some parts like the lower radiator and the reservoir where the liquid got stuck, and I had to resort to flipping the computer upside down and shake to get rid of it.&lt;/p&gt;
&lt;p&gt;Yet again.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/nodrain.jpg&quot; /&gt;
&lt;figcaption&gt;Plenty of liquid left in some weird places.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;It’s alive&lt;/h1&gt;
&lt;p&gt;Building a computer is a little scary because you don’t know if it’s going to work when you’re done.
And especially so with this kind of build, where disassembling would be a major endeavor.&lt;/p&gt;
&lt;p&gt;But it worked!
And it’s glorious!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/back.jpg&quot; /&gt;
&lt;figcaption&gt;Ah, the beautiful cable management.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/side_view.jpg&quot; /&gt;
&lt;figcaption&gt;My 3-year old really enjoys this view.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/top_fans.jpg&quot; /&gt;
&lt;figcaption&gt;The Noctua fans are amazing.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/computer_upgrade/front_fans.jpg&quot; /&gt;
&lt;figcaption&gt;Yes, I replaced all the fans.&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Language spec in code blocks</title><id>http://jonashietala.se/blog/2023/10/06/language_spec_in_code_blocks/index.html</id><updated>2024-07-09T12:10:58+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/06/language_spec_in_code_blocks" rel="alternate"/><published>2023-10-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Even though I just recently &lt;a href=&quot;/blog/2023/10/04/giving_the_blog_a_facelift/&quot;&gt;restyled the blog&lt;/a&gt; and wasn’t going to touch it, there was one thing I wanted to add, but it felt a little bothersome so I skipped it.
It was to display the highlighted language in code blocks:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/code_spec.png&quot; /&gt;
&lt;figcaption&gt;The code spec displays what programming language the code block contains.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As it happens, my little girl—the fountain of joy that never stops giving—decided to not sleep last night.
(I can’t really be angry with her, she’s only 10 months and she’s getting sick.)&lt;/p&gt;
&lt;p&gt;So there I was, carrying her in a harness and trying not to play with her because I just want her to fall asleep.
I usually do this in front of the computer so she can listen to music and fall asleep (her favorite is &lt;strong&gt;In Flames: Only for the Weak&lt;/strong&gt;).
But that’s also time I can use to to work on weird things, and in this case I reworked the code block display.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;This is also how I created the &lt;a href=&quot;/series/t-34/&quot;&gt;T-34 keyboard layout&lt;/a&gt;. Another of our kids was awake for 1–2 hours every night for like half a year, so I filled that time by creating my layout.&lt;/p&gt;
&lt;p&gt;A sleep deprived state is a recipe for doing weird shit.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Previously, code blocks were generated like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;highlight viml&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The problem was that I couldn’t just add a &lt;code&gt;div&lt;/code&gt; inside the &lt;code&gt;pre&lt;/code&gt; tag because I want the code to be scrollable when it overflows:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;pre&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;overflow-wrap&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;normal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;overflow&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;auto&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But then the contents cannot exist partially outside of the tag, since that would be hidden, and scrolling would also move the language spec element.&lt;/p&gt;
&lt;p&gt;So instead I used another &lt;code&gt;div&lt;/code&gt; to wrap everything:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;code-wrapper&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;lang viml&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;highlight viml&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This allows me to use the &lt;code&gt;::before&lt;/code&gt; pseudo-class to insert the language description depending on the class (&lt;code&gt;viml&lt;/code&gt; in this example).
See the relevant styling:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;code-wrapper&lt;/span&gt; &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;lang&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Move the language spec to the right.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;flex&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;justify-content&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;right&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;align-items&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;flex-start&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Use the ::before pseudo-class for the actual language spec.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;keyword operator ampersand sass&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-element css&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;before&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Match the code block style.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta function-call sass&quot;&gt;&lt;span class=&quot;keyword control directive sass&quot;&gt;&lt;span class=&quot;punctuation definition keyword sass&quot;&gt;@&lt;/span&gt;include&lt;/span&gt; &lt;span class=&quot;variable function sass&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;meta function-call arguments sass&quot;&gt;&lt;span class=&quot;punctuation section group begin sass&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string quoted double css&quot;&gt;&lt;span class=&quot;punctuation definition string begin css&quot;&gt;&amp;quot;&lt;/span&gt;s&lt;span class=&quot;punctuation definition string end css&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end sass&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-family&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;variable other sass&quot;&gt;&lt;span class=&quot;punctuation definition variable sass&quot;&gt;$&lt;/span&gt;code-font-family&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--melange_a_ui&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;background-color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--melange_a_float&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Give the text some surrounding space.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--space-3xs&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--space-xs&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;border-radius&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--space-3xs&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--space-3xs&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Offset so it partially overlaps the code block and move it toward the middle a little.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;2&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; This ugly looking things tries to remove the height of the child element,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; so we get consistent spacing around the code block.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-block-start&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--flow-space&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;ch&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--space-xs&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; For each class insert the corresponding language text.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;keyword operator ampersand sass&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;python&lt;/span&gt;&lt;span class=&quot;punctuation definition pseudo-element css&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;entity other pseudo-element css&quot;&gt;before&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;content&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta string css&quot;&gt;&lt;span class=&quot;string quoted double css&quot;&gt;&lt;span class=&quot;punctuation definition string begin css&quot;&gt;&amp;quot;&lt;/span&gt;python&lt;span class=&quot;punctuation definition string end css&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; etc.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The reason I used a pseudo-class for the language description instead of directly like &lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;viml&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; is to hide it from other reading modes, such as the RSS feed, Firefox’s reader view or screen readers.
These readers typically remove most or all of the styling, but then the language description would appear in the middle of nowhere without context.
Using a pseudo-class is a bit annoying as I need to insert some CSS for every single language I want to display, but it provides a better experience for people using these readers.&lt;/p&gt;
&lt;p&gt;I also changed the font to my &lt;a href=&quot;/iosevka&quot;&gt;custom Iosevka&lt;/a&gt; for the website as well.
Now I’m happy with how things look.&lt;/p&gt;
</content></entry><entry><title>Giving the blog a facelift</title><id>http://jonashietala.se/blog/2023/10/04/giving_the_blog_a_facelift/index.html</id><updated>2024-07-09T12:14:25+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/04/giving_the_blog_a_facelift" rel="alternate"/><published>2023-10-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;When I &lt;a href=&quot;/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit/&quot;&gt;rewrote the blog in Rust&lt;/a&gt; I tried not to touch any of the styling, but some things annoyed me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It wasn’t pretty (even ugly in some parts).&lt;/li&gt;
&lt;li&gt;No dark mode support.&lt;/li&gt;
&lt;li&gt;Some elements were broken, for instance images or code blocks overlapping the header when it was floating to the side.&lt;/li&gt;
&lt;li&gt;I wanted to promote my series and projects more.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;A better landing page&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/site_restyle/new_homepage.png&quot; /&gt;
&lt;figcaption&gt;The old landing page was too simple for my taste.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My thinking when &lt;a href=&quot;/blog/2019/01/25/site_restyle_and_update/&quot;&gt;I last updated the style&lt;/a&gt; was to keep things as simple as possible.
I think I mostly succeeded with that, but I really don’t think the landing page was pretty.&lt;/p&gt;
&lt;p&gt;So this time I wanted to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make it prettier&lt;/li&gt;
&lt;li&gt;Spotlight posts, series and projects&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As it happens I had remade the &lt;a href=&quot;/archive&quot;&gt;archive&lt;/a&gt;, &lt;a href=&quot;/projects&quot;&gt;projects&lt;/a&gt; and &lt;a href=&quot;/series&quot;&gt;series&lt;/a&gt; pages already, and it just fell out well to simply include some partial contents and shove them into the homepage.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/facelift/landing_dark.png&quot;&gt;&lt;img src=&quot;/images/facelift/landing_dark.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/facelift/landing_light.png&quot;&gt;&lt;img src=&quot;/images/facelift/landing_light.png&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I’m sure you could make a bunch of improvements, but the design fulfills my goals at least.&lt;/p&gt;
&lt;h1&gt;Automatic dark mode&lt;/h1&gt;
&lt;p&gt;I’ve been using dark mode when coding for ages, but it’s only recently I tried to switch everything to dark by default.&lt;/p&gt;
&lt;p&gt;Some sites use a dark mode switcher button, but I think it’s better if the sites detect your preference automatically.
It’s surprisingly easy in CSS using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme&quot;&gt;prefers-color-scheme&lt;/a&gt;, and here’s a small example:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;root&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--color-text&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant color w3c standard css&quot;&gt;black&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta at-rule media css&quot;&gt;&lt;span class=&quot;keyword control directive css&quot;&gt;&lt;span class=&quot;punctuation definition keyword css&quot;&gt;@&lt;/span&gt;media&lt;/span&gt; &lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type property-name css&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;root&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--color-text&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant color w3c standard css&quot;&gt;white&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Then you just use the variables like so:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;element&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--color-text&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To test this out, in Firefox (and I’m sure other browsers) you can change your preference and the site will update immediately:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/facelift/firefox_settings.png&quot; /&gt;
&lt;figcaption&gt;You can change dark mode preference in Firefox.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/facelift/dark.png&quot;&gt;&lt;img src=&quot;/images/facelift/dark.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/facelift/light.png&quot;&gt;&lt;img src=&quot;/images/facelift/light.png&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I prefer the dark variant, but the light is also quite nice.&lt;/p&gt;
&lt;h1&gt;New colorscheme&lt;/h1&gt;
&lt;p&gt;I recently fell in love with the colorscheme &lt;a href=&quot;https://github.com/savq/melange-nvim&quot;&gt;melange-nvim&lt;/a&gt; for Neovim.
This was a &lt;strong&gt;big deal&lt;/strong&gt; for me so naturally I want to use the colorscheme &lt;em&gt;everywhere&lt;/em&gt;.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/facelift/qr_dark.png&quot;&gt;&lt;img src=&quot;/images/facelift/qr_dark.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/facelift/qr_light.png&quot;&gt;&lt;img src=&quot;/images/facelift/qr_light.png&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;This doesn’t just apply to the code highlighting, but to the colorscheme of the entire blog itself.
Go big or go home.&lt;/p&gt;
&lt;h1&gt;Systematic CSS&lt;/h1&gt;
&lt;p&gt;People love to hate on CSS, and maybe I’m damaged but I quite like CSS.
Things have come a &lt;em&gt;long&lt;/em&gt; way since I styled my first webpage.
Back then you had to do all types of weird incantations even to do simple things, and IE 6 still found a way to mess it up.&lt;/p&gt;
&lt;p&gt;While there are browser incompatibilities today, it’s not nearly as bad and the browsers today support a lot of really nice features that makes modern CSS quite neat.&lt;/p&gt;
&lt;p&gt;Here are some things I utilized this time around:&lt;/p&gt;
&lt;h2&gt;Fluid size scales&lt;/h2&gt;
&lt;p&gt;Sizing fonts is more annoying than one might think.
One thing you’d like to do is to have a slightly larger font for larger screens, and smaller sizes for smaller screens (such as your phone).
It makes it easier to read on both devices, but it’s a bit annoying to setup.&lt;/p&gt;
&lt;p&gt;Previously I used media queries, but a neater solution is fluid size scales.
I just used some generator I found online and it seems to work well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; From https://www.fluid-type-scale.com/
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;root&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--font-size-2xs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;51&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;03&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;5&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;53&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--font-size-xs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;64&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;12&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;61&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;7&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--font-size-s&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;8&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;25&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;74&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;94&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--font-size-m&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;45&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;89&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;25&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--font-size-l&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;25&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;76&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;06&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;67&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--font-size-xl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;56&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;2&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;26&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;22&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--font-size-2xl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;95&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;83&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;5&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;96&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now it’s not perfect, and on my monitor I feel the jump from &lt;code&gt;m&lt;/code&gt; to &lt;code&gt;s&lt;/code&gt; is a bit too big, but this is good enough (for now).&lt;/p&gt;
&lt;p&gt;I also utilize a fluid scale for spacing:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; From https://utopia.fyi/
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;root&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-3xs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;31&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;31&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;31&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-2xs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;56&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;54&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;11&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;63&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-xs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;88&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;85&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;11&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;94&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-s&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;13&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;08&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;22&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;25&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-m&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;69&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;62&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;33&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;88&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-l&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;25&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;16&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;43&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;5&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-xl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;3&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;38&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;3&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;24&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;65&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;3&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;75&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--space-2xl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;clamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;4&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;5&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;calc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;4&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;33&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;87&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;vw&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;rem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Lobotomized owl&lt;/h2&gt;
&lt;p&gt;It’s always fun to find weird things that are also very useful.
The &lt;a href=&quot;https://alistapart.com/article/axiomatic-css-and-lobotomized-owls/&quot;&gt;lobotimized owl&lt;/a&gt; selector is just that.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Hoot-hoot
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;     &lt;span class=&quot;variable language wildcard asterisk css&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;keyword operator combinator css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;variable language wildcard asterisk css&quot;&gt;*&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For a great explanation see &lt;a href=&quot;https://andy-bell.co.uk/my-favourite-3-lines-of-css/&quot;&gt;My favourite 3 lines of CSS&lt;/a&gt;,
but in short it enables you to set consistent spacing between child elements.&lt;/p&gt;
&lt;p&gt;It’s super useful, and I use this mixin for it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function declaration sass&quot;&gt;&lt;span class=&quot;keyword control directive sass&quot;&gt;&lt;span class=&quot;punctuation definition keyword sass&quot;&gt;@&lt;/span&gt;mixin&lt;/span&gt; &lt;span class=&quot;entity name function sass&quot;&gt;flow&lt;/span&gt;&lt;span class=&quot;meta function parameters sass&quot;&gt;&lt;span class=&quot;punctuation section group begin sass&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter sass&quot;&gt;&lt;span class=&quot;punctuation definition variable sass&quot;&gt;$&lt;/span&gt;space&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant language sass&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation section group end sass&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;keyword operator ampersand sass&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;keyword operator combinator css&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;variable language wildcard asterisk css&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;keyword operator combinator css&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;variable language wildcard asterisk css&quot;&gt;*&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-block-start&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--flow-space&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta at-rule sass&quot;&gt;&lt;span class=&quot;keyword control flow conditional sass&quot;&gt;&lt;span class=&quot;punctuation definition keyword sass&quot;&gt;@&lt;/span&gt;if&lt;/span&gt; &lt;span class=&quot;variable other sass&quot;&gt;&lt;span class=&quot;punctuation definition variable sass&quot;&gt;$&lt;/span&gt;space&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--flow-space&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;variable other sass&quot;&gt;&lt;span class=&quot;punctuation definition variable sass&quot;&gt;$&lt;/span&gt;space&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Why didn’t I use the &lt;a href=&quot;https://andy-bell.co.uk/my-favourite-3-lines-of-css/&quot;&gt;stack + flow&lt;/a&gt; as described in the linked blog post?
Honestly, I had forgot about it and only searched for the post now as I’m writing this.
Their way is probably better, but I can’t be bothered to refactor it right now. 🤷&lt;/p&gt;
&lt;h2&gt;Measure to limit text width&lt;/h2&gt;
&lt;p&gt;A big readability tip is to &lt;a href=&quot;https://practicaltypography.com/line-length.html&quot;&gt;limit the line length to 45–90 characters&lt;/a&gt;.
I do this using &lt;code&gt;max-inline-size&lt;/code&gt; and a variable to control the length that’s on by default:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;punctuation definition pseudo-class css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;entity other pseudo-class css&quot;&gt;root&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Measure limits the width of text to be more readable.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;entity other custom-property css&quot;&gt;--measure&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;ch&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;variable language wildcard asterisk css&quot;&gt;*&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Limit everything to --measure by default.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;max-inline-size&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--measure&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Opt-out instead of opt-in, makes it a bit more manageable honestly.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;nav&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;pre&lt;/span&gt; &lt;span class=&quot;entity name tag html css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;pre&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;max-inline-size&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;none&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If I want to use a different line length I can just alter &lt;code&gt;--measure&lt;/code&gt;, or override &lt;code&gt;max-inline-size&lt;/code&gt; if I don’t want it for some elements.&lt;/p&gt;
&lt;h2&gt;CSS Grid is awesome&lt;/h2&gt;
&lt;p&gt;I haven’t used &lt;a href=&quot;https://css-tricks.com/snippets/css/complete-guide-grid/&quot;&gt;grid&lt;/a&gt; that much previously, but it’s one of these newer features that makes CSS a pleasure rather than a pain to work with.
You can accomplish things that were previously hard to do with just some commands.
Here are some examples of how I use grid:&lt;/p&gt;
&lt;h3&gt;Image gallery: 3-column layout&lt;/h3&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/facelift/gallery.png&quot; /&gt;
&lt;figcaption&gt;A 3-column layout with grid.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;gallery&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;grid-template-columns&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function grid css&quot;&gt;repeat&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;fr&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;grid-gap&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--space-3xs&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Tags: variable number of columns&lt;/h3&gt;
&lt;p&gt;If you want to fit as many columns as possible, you can use this setup that I use on the &lt;a href=&quot;/blog/tags&quot;&gt;tags page&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;tags&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;grid-template-columns&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function grid css&quot;&gt;repeat&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword other grid css&quot;&gt;auto-fit&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function grid css&quot;&gt;minmax&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;fr&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Post: overflow images and code blocks&lt;/h3&gt;
&lt;p&gt;Constraining the width of text is good, but I wanted to allow images and code blocks to extend past that a little if needed. See this image:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/facelift/grid_article.png&quot; /&gt;
&lt;figcaption&gt;Most content exists between grid lines 3 and 4, but the image may span between lines 2 and 5, essentially overflowing the article width.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In my previous design I used media queries and relative offsets to accomplish it, but with grid it’s easier and fluent.
With this setup you can also allow an image to extend the entire screen (“full bleed”), but so far I haven’t find a use for it.&lt;/p&gt;
&lt;p&gt;The main &lt;code&gt;article&lt;/code&gt; includes this wrapper:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function declaration sass&quot;&gt;&lt;span class=&quot;keyword control directive sass&quot;&gt;&lt;span class=&quot;punctuation definition keyword sass&quot;&gt;@&lt;/span&gt;mixin&lt;/span&gt; &lt;span class=&quot;entity name function sass&quot;&gt;full-bleed-wrapper&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;grid&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;grid-template-columns&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;fr&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function grid css&quot;&gt;minmax&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--overflow-size&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function calc css&quot;&gt;min&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--measure&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function grid css&quot;&gt;minmax&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator sequence css&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function-call identifier css&quot;&gt;&lt;span class=&quot;support function var css&quot;&gt;var&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments css&quot;&gt;&lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other custom-property css&quot;&gt;--overflow-size&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;fr&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;max-inline-size&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;none&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; Place all content in the main content area by default
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;keyword operator ampersand sass&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;keyword operator combinator css&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;variable language wildcard asterisk css&quot;&gt;*&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;grid-column&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This sets up 5 areas: the main middle content, constrained by &lt;code&gt;--measure&lt;/code&gt;, the overflow with &lt;code&gt;--overflow-size&lt;/code&gt; and the rest.
On narrow screens everything except the content collapses to zero width.&lt;/p&gt;
&lt;p&gt;Then you override &lt;code&gt;grid-column&lt;/code&gt; for the items you want to overflow:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; For overflowing the article.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function declaration sass&quot;&gt;&lt;span class=&quot;keyword control directive sass&quot;&gt;&lt;span class=&quot;punctuation definition keyword sass&quot;&gt;@&lt;/span&gt;mixin&lt;/span&gt; &lt;span class=&quot;entity name function sass&quot;&gt;overflow-bleed&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;grid-column&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;5&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword other important css&quot;&gt;!important&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; This resets the --measure constrain I have on by default.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;max-inline-size&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;none&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; For items that should span the entire screen.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function declaration sass&quot;&gt;&lt;span class=&quot;keyword control directive sass&quot;&gt;&lt;span class=&quot;punctuation definition keyword sass&quot;&gt;@&lt;/span&gt;mixin&lt;/span&gt; &lt;span class=&quot;entity name function sass&quot;&gt;full-bleed&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;grid-column&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic css&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword other important css&quot;&gt;!important&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;max-inline-size&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;none&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mixins like these are why I prefer &lt;a href=&quot;https://sass-lang.com/&quot;&gt;sass&lt;/a&gt; over raw CSS, it makes creating these systems more practical and maintainable.&lt;/p&gt;
&lt;h1&gt;What am I not satisfied with?&lt;/h1&gt;
&lt;p&gt;I quite like sitting and making small tweaks until I like how things look.
Even if the process can be slow I still enjoy it.&lt;/p&gt;
&lt;p&gt;But I really don’t like how brittle it feels.
I’ve tried to namespace rules, so in &lt;code&gt;css/local/_tags.scss&lt;/code&gt; I have rules only for the tags page:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag html css&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;tags-list&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;  &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;tags&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash sass&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;//&lt;/span&gt; ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But most things are shared across pages, and if I make a change somewhere I may accidentally break some obscure styling somewhere.
Having unit tests for the layout would be nice, but I’m not keen of maintaining a rendering of all pages and doing an image diff to find errors.&lt;/p&gt;
&lt;p&gt;Of course I could make everything local, but then I’d miss out on the usefulness of the general rules, and the maintenance burden would be even higher.&lt;/p&gt;
&lt;p&gt;Maybe I’ll just leave the styling alone for the next couple of years until I feel I want to remake everything again?&lt;/p&gt;
</content></entry><entry><title>Rewriting my Neovim config in Lua</title><id>http://jonashietala.se/blog/2023/10/01/rewriting_my_neovim_config_in_lua/index.html</id><updated>2025-01-19T07:16:57+00:00</updated><link href="https://www.jonashietala.se/blog/2023/10/01/rewriting_my_neovim_config_in_lua" rel="alternate"/><published>2023-10-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/splash.png&quot;&gt;
&lt;figcaption&gt;This screenshot betrays just how much productive time was wasted setting this up.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I’ve got tons of things to do; clean the bathrooms, prototype an idea for a SaaS and ponder world peace.
So naturally the procrastination took over and I rewrote my Neovim configuration in Lua.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/cool_kids_lua.jpg&quot;&gt;
&lt;/figure&gt;
&lt;section id=&quot;But-why&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#But-why&quot; class=&quot;heading-ref&quot;&gt;But why?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No, but seriously, I’ve had my Neovim configuration since before Neovim existed and it’s been working fine.
Why would I then rewrite it, and using Lua to boot?&lt;/p&gt;
&lt;p&gt;My config has collected a lot of cruft over the years, and it was about time to do a cleanup.
So I figured the best way was to do it all from scratch, only adding things from the old config if I really needed them (and if I knew what they were doing there!).&lt;/p&gt;
&lt;p&gt;I was also curious on how well it would work to configure Neovim using Lua instead of Vimscript, and if there were some new fancy things I was missing.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Just-a-few-plugins-or-many&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Just-a-few-plugins-or-many&quot; class=&quot;heading-ref&quot;&gt;Just a few plugins or many?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As is common knowledge, there are these great divides in the developer community.
Issues so great that it makes the Israeli-Palestinian conflict feel like kids fighting in the sandbox.&lt;/p&gt;
&lt;p&gt;I’m of course talking about the age-old questions of Vim vs Emacs, if you should use an IDE or a Text Editor and &lt;strong&gt;gasp&lt;/strong&gt; if you should use tabs or spaces.&lt;/p&gt;
&lt;p&gt;And even inside the Vim community we have our own great question:
should you amass as many plugins as possible, pimping out your Vim so it can be mistaken for an IDE, 
or should you keep it minimalistic, staying true to the Raw Vim experience?&lt;/p&gt;
&lt;p&gt;So where do I stand in this?
On which hill will I die on?&lt;/p&gt;
&lt;p&gt;As I’m writing this I’m up to 77 plugins, with a bunch more on my “plugins to check” list, so I guess I’m dying on the “&lt;strong&gt;use all the plugins&lt;/strong&gt;” hill.&lt;/p&gt;
&lt;p&gt;If that makes you feel like I’ve betrayed Bram the creator, then my only defense is this:&lt;/p&gt;
&lt;p&gt;I tried, but I failed.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Where-to-start&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Where-to-start&quot; class=&quot;heading-ref&quot;&gt;Where to start?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The inspiration for this was ThePrimeagen’s video on &lt;a href=&quot;https://www.youtube.com/watch?v=w7i4amO_zaE&quot;&gt;0 to LSP: Neovim RC From Scratch&lt;/a&gt; that I watched several months ago.&lt;/p&gt;
&lt;p&gt;While ThePrimeagen’s video was great as inspiration (look how easy it is!), I don’t think it’s the best configuration to reference.
I instead used other sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/LazyVim/LazyVim/tree/main&quot;&gt;LazyVim&lt;/a&gt; is a popular Neovim distro that you can use if you don’t want to configure everything from scratch or—the horror—anything at all.&lt;/p&gt;
&lt;p&gt;A distro is absolutely not my thing, but the &lt;a href=&quot;https://github.com/LazyVim/LazyVim/tree/main&quot;&gt;LazyVim&lt;/a&gt; source was quite useful as a reference for me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Distros may be overkill, a better alternative might be the small configurations that are made to help you get going with your own config.&lt;/p&gt;
&lt;p&gt;Take a look at &lt;a href=&quot;https://github.com/nvim-lua/kickstart.nvim&quot;&gt;kickstart.nvim&lt;/a&gt; and &lt;a href=&quot;https://github.com/NvChad/tinyvim&quot;&gt;TinyVim&lt;/a&gt; for example.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There are lots of people who have their configs on GitHub.&lt;/p&gt;
&lt;p&gt;I used &lt;a href=&quot;https://github.com/catgoose/nvim&quot;&gt;catgoose&lt;/a&gt; as the config was really clean, including lots of plugins to inspire me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Speaking of plugins, &lt;a href=&quot;https://neovimcraft.com/&quot;&gt;neovimcraft&lt;/a&gt; is a good site to find plugins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://dotfyle.com/&quot;&gt;dotfyle&lt;/a&gt; is another great site with plugins, configurations and the fantastic &lt;a href=&quot;https://dotfyle.com/this-week-in-neovim&quot;&gt;This Week in Neovim&lt;/a&gt; newsletter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Structured-configuration&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Structured-configuration&quot; class=&quot;heading-ref&quot;&gt;Structured configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the big problems with my previous setup was that &lt;code&gt;init.vim&lt;/code&gt; was huge and it was hard to organize it. I tried using folds and having a logical grouping, but it never felt good.&lt;/p&gt;
&lt;p&gt;With lua and &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; you can organize settings and plugins in different files quite nicely. This is how I did it:&lt;/p&gt;
&lt;p&gt;I wanted to have a split of &lt;code&gt;config/&lt;/code&gt; and &lt;code&gt;plugins/&lt;/code&gt;, so &lt;code&gt;~/.config/nvim/init.lua&lt;/code&gt; just loads &lt;code&gt;~/.config/nvim/lua/config/init.lua&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then in &lt;code&gt;~/.config/nvim/lua/config/init.lua&lt;/code&gt; I load the configurations and plugin manager:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Setup &amp;lt;leader&amp;gt; and &amp;lt;localleader&amp;gt; before loading plugins
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.leader&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Use lazy.nvim for plugin management
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.lazy&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Continue with the configuration, possibly overriding settings that some
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; plugins might set.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.options&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.colorscheme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.keymaps&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).init()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.commands&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; you can split up plugin specifications into separate files:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Basic lazy.nvim setup as copied from the readme
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; lazypath &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.stdpath(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;data&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/lazy/lazy.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;not&lt;/span&gt; vim.loop.fs_stat(lazypath) &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  vim.fn.system({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;git&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;clone&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;--filter=blob:none&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;https://github.com/folke/lazy.nvim.git&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;--branch=stable&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; latest stable release
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    lazypath,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.opt.rtp:prepend(lazypath)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Load plugin specs from lua/plugins/*.lua
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;lazy&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).setup(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;plugins&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  defaults &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    lazy &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Default to lazy loading, optional
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  change_detection &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    notify &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt;, &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; I find the config changed notification super annoying
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will automatically load any &lt;code&gt;.lua&lt;/code&gt; file in the &lt;code&gt;lua/plugins&lt;/code&gt; folder. For example this is &lt;code&gt;lua/plugins/replacer.lua&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;gabrielpoca/replacer.nvim&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  opts &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { rename_files &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt; },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  keys &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.keymaps&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).replacer,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Incredibly nice when you have lots of plugins, and some have large configurations (like &lt;a href=&quot;https://github.com/neovim/nvim-lspconfig&quot;&gt;lspconfig&lt;/a&gt;, &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;treesitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;cmp&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;One last big thing is I wanted to have all global keymaps in one single file. &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; supports adding keymaps in the plugin specification using 
&lt;code class=&quot;highlight lua&quot;&gt;keys &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; { }&lt;/code&gt; option. I accomplished this by simply returning a “module” table from &lt;code&gt;config/keymaps.lua&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;M &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;M.replacer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;leader&amp;gt;rq&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;replacer&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).run()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    silent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Make quickfix editable for replacing in&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  },
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; And other plugin keymaps like this
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;M.trouble &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; M
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not all keymaps can be defined using the &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; specification, in which case I returned a function and called that where applicable. For instance for LSP:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;M.buf_lsp &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(_, buffer)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; map &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.keymap.set
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;localleader&amp;gt;D&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, vim.lsp.buf.declaration, { silent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, buffer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; buffer, desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Declaration&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;localleader&amp;gt;d&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, vim.lsp.buf.definition, { silent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, buffer &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; buffer, desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Definition&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; etc
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And set it up in &lt;code&gt;plugins/lspconfig.lua&lt;/code&gt; in the &lt;code&gt;on_attach&lt;/code&gt; callback:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; on_attach &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(client, buffer)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  keymaps.buf_lsp(client, buffer) &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Will add the keymaps when LSP attaches to the buffer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  lsp_status.on_attach(client)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One last thing; for the regular mappings you don’t want to just remap them in &lt;code&gt;config/keymaps.lua&lt;/code&gt; because multiple files will run 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.keymaps&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;/code&gt;, so I wrapped it in an init function:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;M.init &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; map &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.keymap.set
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;leader&amp;gt;p&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted single lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;#39;&lt;/span&gt;&amp;quot;*p&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;, { silent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Paste from mouse&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;leader&amp;gt;P&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted single lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;#39;&lt;/span&gt;&amp;quot;*P&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;, { silent &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;, desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Paste before from mouse&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; etc
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is why &lt;code&gt;config/init.lua&lt;/code&gt; looked a bit weird:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.options&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.colorscheme&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.keymaps&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).init() &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Notice the weird init() call here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.commands&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s true that &lt;code&gt;keymaps.lua&lt;/code&gt; has grown quite large and isn’t super easy to read. Maybe I’ll break it out into more keymap files (&lt;code&gt;config/keymaps/lsp.lua&lt;/code&gt; etc) in the future, but right now I think it’s nice to have all the maps in one single file.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Favorite-new-to-me-plugins&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Favorite-new-to-me-plugins&quot; class=&quot;heading-ref&quot;&gt;Favorite new-to-me plugins&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While doing the rewrite I went through my existing plugins to see if they were still relevant, or if I could replace or just remove them. And of course, if I could add some new ones.&lt;/p&gt;
&lt;p&gt;I won’t create a list of my favorite plugins, as it would be boring to see yet another list with &lt;a href=&quot;https://github.com/neovim/nvim-lspconfig&quot;&gt;LSP&lt;/a&gt;, &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter&quot;&gt;treesitter&lt;/a&gt; and &lt;a href=&quot;https://github.com/hrsh7th/nvim-cmp&quot;&gt;cmp&lt;/a&gt;, I’ll instead highlight some good plugins that were new to me:&lt;/p&gt;
&lt;section id=&quot;lazynvim-A-modern-plugin-manager&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#lazynvim-A-modern-plugin-manager&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt;: A modern plugin manager&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/lazy.png&quot;&gt;
&lt;figcaption&gt;Observe the glory of a modern package manager
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I’ve been using &lt;a href=&quot;https://github.com/junegunn/vim-plug&quot;&gt;vim-plug&lt;/a&gt; as my plugin manager since forever. It’s been working well, but I figured I should try one of these newer managers to see if I was missing something. And boy, did I. &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; has some really nice features that I now can’t live without:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Split plugin specifications in separate files as I wrote about &lt;a href=&quot;#Structured-configuration&quot;&gt;earlier in the post&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
Specify plugin dependencies.
&lt;/li&gt;
&lt;li&gt;
Pin plugin versions.
&lt;/li&gt;
&lt;li&gt;
Track plugin versions in &lt;code&gt;lazy-lock.json&lt;/code&gt;, so you can identify what plugin version breaks your setup so you can pin it to a known good version.
&lt;/li&gt;
&lt;li&gt;
Lazy loading. It’s nice to have for those rarely used but heavy plugins.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;melange-nvim-An-amazing-colorscheme&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#melange-nvim-An-amazing-colorscheme&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/savq/melange-nvim&quot;&gt;melange-nvim&lt;/a&gt;: An amazing colorscheme&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/melange2.png&quot;&gt;
&lt;figcaption&gt;It’s just pleasing to my eyes.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/melange3.png&quot;&gt;
&lt;figcaption&gt;The design idea is that control flow should use warm colors and data should use cold colors.
So here, functions are warm yellow and strings and data are colder purple and green.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I’ve been a gruvbox user since I started using Vim almost 15 years ago. I’ve tried tons of different colorschemes but nothing has ever come close to gruvbox for me. Most of the popular colorschemes are just too blue, or have too little (or too much) contrast or I just don’t like them for some random reason.&lt;/p&gt;
&lt;p&gt;I had almost resigned to becoming a gruvbox-lifer, unable to ever change colorscheme.&lt;/p&gt;
&lt;p&gt;And then, &lt;a href=&quot;https://github.com/savq/melange-nvim&quot;&gt;melange-nvim&lt;/a&gt; appeared. And it’s glorious!
Now after many long years, I’ve finally switched to a new colorscheme, and I’m content.&lt;/p&gt;
&lt;p&gt;(No, switching from the original &lt;a href=&quot;https://github.com/morhetz/gruvbox&quot;&gt;gruvbox&lt;/a&gt; to &lt;a href=&quot;https://github.com/ellisonleao/gruvbox.nvim&quot;&gt;gruvbox.nvim&lt;/a&gt; to &lt;a href=&quot;https://github.com/sainnhe/gruvbox-material&quot;&gt;gruvbox-material&lt;/a&gt; and back again doesn’t count.)&lt;/p&gt;
&lt;p&gt;Also a shout-out to &lt;a href=&quot;https://github.com/rebelot/kanagawa.nvim&quot;&gt;kanagawa&lt;/a&gt; (dragon, the dark variant without blue background) which is the only colorscheme I’ve found that I didn’t eject in horror after 5 minutes, except for gruvbox and melange.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/kanagawa.png&quot;&gt;
&lt;figcaption&gt;Sorry &lt;a href=&quot;https://github.com/rebelot/kanagawa.nvim&quot;&gt;kanagawa&lt;/a&gt;. It’s not you, it’s me.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;vim-cool-Turn-off-search-highlight&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#vim-cool-Turn-off-search-highlight&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/romainl/vim-cool&quot;&gt;vim-cool&lt;/a&gt;: Turn off search highlight&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Forget &lt;code&gt;&amp;lt;C-l&amp;gt;&lt;/code&gt;, this plugin will turn off search highlight when you move your cursor away from it.
Simple, but raises the quality of life a &lt;strong&gt;lot&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;conform-Format-on-save&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#conform-Format-on-save&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/stevearc/conform.nvim&quot;&gt;conform&lt;/a&gt;: Format on save&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve used &lt;a href=&quot;https://github.com/sbdchd/neoformat&quot;&gt;neoformat&lt;/a&gt; before, but had some issues where I saved then quickly stared modifying something, but then formating kicked in and removed my changes.&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/stevearc/conform.nvim&quot;&gt;conform&lt;/a&gt; I haven’t had these issues, and configuration was quick and easy and LSP fallback is super sweet. Excellent plugin.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;nvim-treesitter-textobjects&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#nvim-treesitter-textobjects&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter-textobjects&quot;&gt;nvim-treesitter-textobjects&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A common misconception about treesitter is that it only adds semantics to syntax highlighting:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/base_layout.png&quot;&gt;
&lt;figcaption&gt;BASE and REPEAT are enum members, while the other keycodes are defined as macros.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I think that’s very nice, but treesitter is more than that. And a great example of that is &lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter-textobjects&quot;&gt;nvim-treesitter-textobjects&lt;/a&gt; where you can operate on treesitter nodes. I have for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;]f&lt;/code&gt; jump to next function.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;]c&lt;/code&gt; jump to next class.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;]g&lt;/code&gt; jump to next function or class.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;s&lt;/code&gt; swap next parameter.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;if&lt;/code&gt; textobject for inner function. So &lt;code&gt;cif&lt;/code&gt; would delete the function body and enter insert mode.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ax&lt;/code&gt; textobject for outer comment, to easily delete/change comments.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The beauty is that these work on treesitter nodes, so they work equally well across languages for functions like 
&lt;code class=&quot;highlight rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;myfun&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;, 
&lt;code class=&quot;highlight lua&quot;&gt;&lt;span class=&quot;meta function lua&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;entity name function lua&quot;&gt;myfun&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters begin lua&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters end lua&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;&lt;/code&gt; or a 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;meta function elixir&quot;&gt;&lt;span class=&quot;keyword control module elixir&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity name function public elixir&quot;&gt;myfun&lt;/span&gt;&lt;span class=&quot;punctuation definition parameters elixir&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section function elixir&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;keyword control module elixir&quot;&gt;do&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator range elixir&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;end&lt;/span&gt;&lt;/code&gt;. (Given that the treesitter implementation supports these options. Markdown doesn’t have the concept of a function for instance.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Neogit-Git-management&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Neogit-Git-management&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/NeogitOrg/neogit&quot;&gt;Neogit&lt;/a&gt;: Git management&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://magit.vc/&quot;&gt;magit&lt;/a&gt; is widely regarded as the best Git client/integration there is.
When I used Emacs for work (oh yes, the horrors) I did use &lt;a href=&quot;https://magit.vc/&quot;&gt;magit&lt;/a&gt; and yes it was great (although too slow on Windows).&lt;/p&gt;
&lt;p&gt;I don’t think I need to say more than that &lt;a href=&quot;https://github.com/NeogitOrg/neogit&quot;&gt;Neogit&lt;/a&gt; is &lt;a href=&quot;https://magit.vc/&quot;&gt;magit&lt;/a&gt;, but for Neovim, and it is also great.
(It doesn’t have feature parity with &lt;a href=&quot;https://magit.vc/&quot;&gt;magit&lt;/a&gt; yet, but it’s good enough to have replaced &lt;a href=&quot;https://github.com/tpope/vim-fugitive&quot;&gt;fugitive&lt;/a&gt; for me.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;alpha-nvim-Dashboard&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#alpha-nvim-Dashboard&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/goolord/alpha-nvim&quot;&gt;alpha-nvim&lt;/a&gt;: Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/alpha.png&quot;&gt;
&lt;figcaption&gt;My startup screen
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I’m going to be honest here: I’ve always thought that a dashboard was unnecessary fluff and people who used them were just pimping Neovim for the sake of pimping.&lt;/p&gt;
&lt;p&gt;And now, I also use a dashboard.&lt;/p&gt;
&lt;p&gt;While it’s something I could absolutely live without, by now I’d rather have it than not.&lt;/p&gt;
&lt;p&gt;Okay, saving a keypress by using &lt;code&gt;f&lt;/code&gt; instead &lt;code&gt;&amp;lt;leader&amp;gt;f&lt;/code&gt; isn’t a big deal.
And yeah, showing &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; stats is probably unnecessary.&lt;/p&gt;
&lt;p&gt;But having a list of keymaps that I should internalize is actually really nice.
It helps remind me of these cool new keymaps I’ve added, so they don’t get forgotten for years until my next config rewrite.&lt;/p&gt;
&lt;p&gt;Yes, the list of keymaps is currently just hardcoded in the dashboard config.
But I would like to implement keymap tracking and use it for spaced repetition.
Maybe even have a floating window on startup that you need to clear every day, similar to “flashcards”.
This is a nice idea for a plugin that I may or may not write in the future…&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;flashnvim-Navigational-plugin&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#flashnvim-Navigational-plugin&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/folke/flash.nvim&quot;&gt;flash.nvim&lt;/a&gt;: Navigational plugin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once upon a time there was &lt;a href=&quot;https://github.com/justinmk/vim-sneak&quot;&gt;vim-sneak&lt;/a&gt; that added the motion &lt;code&gt;s&lt;/code&gt; to jump to any location by specifying two characters.
It was great, and it spawned a slew of other similar plugins that expanded on the idea.
(I’m not sure this is completely historically accurate, but it felt like a good narrative.)&lt;/p&gt;
&lt;p&gt;The plugin I’ve landed on is &lt;a href=&quot;https://github.com/folke/flash.nvim&quot;&gt;flash.nvim&lt;/a&gt;.
What I really like about it is the idea of typing as many characters as possible.
Even with sneak I didn’t always arrive where I wanted, so having the option of typing out more things felt good for me.&lt;/p&gt;
&lt;p&gt;Extra functionality such as doing a “remote yank” (search, yank something, then cursor goes back to where it was) and enhancing &lt;code&gt;f&lt;/code&gt;/&lt;code&gt;F&lt;/code&gt;/&lt;code&gt;t&lt;/code&gt;/&lt;code&gt;T&lt;/code&gt;/&lt;code&gt;/&lt;/code&gt; is just gravy.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;nvim-colorizer-Colorizer-plugin&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#nvim-colorizer-Colorizer-plugin&quot; class=&quot;heading-ref&quot;&gt;&lt;a href=&quot;https://github.com/NvChad/nvim-colorizer.lua&quot;&gt;nvim-colorizer&lt;/a&gt;: Colorizer plugin&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rewrite_neovim_lua/colorizer.png&quot;&gt;
&lt;figcaption&gt;What are these colors again? It’s the palette of &lt;a href=&quot;https://github.com/savq/melange-nvim&quot;&gt;melange-nvim&lt;/a&gt; of course!
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;After &lt;a href=&quot;https://github.com/RRethy/vim-hexokinase&quot;&gt;vim-hexokinase&lt;/a&gt; got archived I had a minor panic.
It was a neat little plugin that highlighted colors inline, but without altering the highlight of the colors themselves, which is what all the other colorizer plugins seemed to do.&lt;/p&gt;
&lt;p&gt;Luckily I found &lt;a href=&quot;https://github.com/NvChad/nvim-colorizer.lua&quot;&gt;nvim-colorizer&lt;/a&gt; that does the same, and without having to build an external binary like hexokinase that always managed to break for some weird reason.&lt;/p&gt;
&lt;p&gt;I love when things just work.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Custom-behavior&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Custom-behavior&quot; class=&quot;heading-ref&quot;&gt;Custom behavior&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Becoming a Pokémon master by collecting all the plugins is great, but one of the benefits of Lua over Vimscript is that it’s a much nicer language for general programming. While I haven’t really taken advantage of it that much yet, I’ve made a small addition that worked quite well for me.&lt;/p&gt;
&lt;p&gt;I’m trying out &lt;a href=&quot;https://github.com/nvim-neorg/neorg&quot;&gt;neorg&lt;/a&gt; as my knowledge base and note taking and I’ve separated it into four folders:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;~/norg/projects
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;~/norg/areas
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;~/norg/resources
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;~/norg/archive
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don’t remember where I saw this recommendation, but it made some sense to me at the time.&lt;/p&gt;
&lt;p&gt;What I want to do with this is either:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Open a file in one of these folders
&lt;/li&gt;
&lt;li&gt;
If no file exists, create and open one
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I could make shell scripts and use fzf as a fuzzy finder, but as I kind of live in Neovim I wanted to do this from within Neovim.&lt;/p&gt;
&lt;p&gt;Using &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;telescope&lt;/a&gt; (fuzzy finder) and &lt;a href=&quot;https://github.com/nvim-lua/plenary.nvim&quot;&gt;plenary&lt;/a&gt; (path helpers) this is what I came up with:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Find files using telescope in a subfolder of `~/norg`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; @param base_folder: string: base folder
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;M.open_norg &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(base_folder)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; action_state &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.actions.state&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; actions &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.actions&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; Path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;plenary.path&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; folder &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.expand(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;~/norg/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; base_folder &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;telescope.builtin&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).find_files({
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    attach_mappings &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;(prompt_bufnr, map)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Creates a file using the telescope input prompt.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Useful to quickly create a file if nothing exists.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; create_file &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; It ain&amp;#39;t pretty... But maybe it&amp;#39;s good enough...? T.T
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; current_picker &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; action_state.get_current_picker(prompt_bufnr)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; input &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; folder &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; current_picker:_get_prompt() &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;.norg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; file &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; Path:new(input)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; file:exists() &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        file:touch({ parents &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        actions.close(prompt_bufnr)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;e &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; file &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;| w&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;i&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;C-e&amp;gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, create_file)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword control lua&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    cwd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; folder,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m sure this can be improved upon in many ways, but it serves the purpose at least.
&lt;code&gt;&amp;lt;C-e&amp;gt;&lt;/code&gt; is used to create the file, as sometimes telescope finds similar files so creating a new file if telescope is empty doesn’t really work.&lt;/p&gt;
&lt;p&gt;Another related function I wanted is to create a weekly journal file. There is support for a daily journal in &lt;a href=&quot;https://github.com/nvim-neorg/neorg&quot;&gt;neorg&lt;/a&gt;, but I specifically wanted a weekly one.
This is how I made it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Open a weekly journal in `~/norg/areas/weekly_journal/`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Create using a template from `~/norg/areas/weekly_journal/template.norg` unless it exists.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;M.open_weekly_journal &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; Path &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;plenary.path&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Should probably make this more general in the future.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; pwd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.fn.expand(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;~/norg/areas/weekly_journal/&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; journal_file &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; pwd &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;support function library lua&quot;&gt;os.date&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;w%W&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;.norg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; file &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; Path:new(journal_file)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;not&lt;/span&gt; file:exists() &lt;span class=&quot;keyword control lua&quot;&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; template &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; Path:new(pwd &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;template.norg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    template:copy({ destination &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; file, override &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;false&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  vim.cmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;e &lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; journal_file &lt;span class=&quot;keyword operator lua&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;| w&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As a bonus here’s how I created a fish alias to start Neovim and call the above functions that are defined in &lt;code&gt;~/.config/nvim/lua/config/norg.lua&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;alias&lt;/span&gt; ep &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim -c &lt;span class=&quot;string escape&quot;&gt;\&amp;quot;&lt;/span&gt;:lua require(&amp;#39;config.norg&amp;#39;).open_norg(&amp;#39;projects&amp;#39;)&lt;span class=&quot;string escape&quot;&gt;\&amp;quot;&lt;/span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;alias&lt;/span&gt; ej &lt;span class=&quot;string&quot;&gt;&amp;quot;nvim -c &lt;span class=&quot;string escape&quot;&gt;\&amp;quot;&lt;/span&gt;:lua require(&amp;#39;config.norg&amp;#39;).open_weekly_journal()&lt;span class=&quot;string escape&quot;&gt;\&amp;quot;&lt;/span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The weird mnemonics are the same I use from within Neovim, so &lt;code&gt;&amp;lt;leader&amp;gt;ep&lt;/code&gt; opens telescope in &lt;code&gt;~/norg/projects&lt;/code&gt; for example.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Is-lua-worth-it&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Is-lua-worth-it&quot; class=&quot;heading-ref&quot;&gt;Is lua worth it?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One reason why I didn’t convert to Lua until now is that to me it looked fairly verbose.&lt;/p&gt;
&lt;p&gt;Even though Vimscript isn’t a good programming language, it’s still a DSL specifically for Vim so it’s quite easy to do common things like set options or add autocommands.
And Lua is nice, but it doesn’t support adding a custom DSL on quite that level, so I was worried I’d have to bend over too much to accomplish things.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;lua&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight lua&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Having to specify `vim.opt` isn&amp;#39;t too bad
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;vim.opt.relativenumber &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;vim.opt.number &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Autocommand creation is slightly more verbose,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; but they&amp;#39;re also a bit more readable than the Vim equivalent in my opinion.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; autocmd &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.api.nvim_create_autocmd
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; augroup &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.api.nvim_create_augroup
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;autocmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;TextYankPost&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  callback &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control lua&quot;&gt;function&lt;/span&gt;()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    vim.highlight.on_yank()
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword control lua&quot;&gt;end&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Briefly highlight yanked text&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; augroup(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;yank&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { clear &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; Hide statusline on dashboard
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;autocmd(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;FileType&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  pattern &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;alpha&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  group &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; augroup(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;filegroup&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { clear &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; }),
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  command &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;setlocal laststatus=0 noruler&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;})
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; It&amp;#39;s true that keymaps are also a more verbose, and having to wrap things
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-dash lua&quot;&gt;&lt;span class=&quot;punctuation definition comment lua&quot;&gt;--&lt;/span&gt; in strings here and there is slightly annoying.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;keyword control lua&quot;&gt;local&lt;/span&gt; map &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; vim.keymap.set
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;(&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;[&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { remap &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant language lua&quot;&gt;true&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;]q&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;:cnext&amp;lt;cr&amp;gt;&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, { desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;Next quickfix&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;map(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;leader&amp;gt;ej&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;support function lua&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;config.norg&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).open_weekly_journal, { desc &lt;span class=&quot;keyword operator lua&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double lua&quot;&gt;&lt;span class=&quot;punctuation definition string begin lua&quot;&gt;&amp;quot;&lt;/span&gt;This weeks journal&lt;span class=&quot;punctuation definition string end lua&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; })
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While the above examples are more verbose than the Vimscript alternatives, it doesn’t feel &lt;strong&gt;that&lt;/strong&gt; bad.&lt;/p&gt;
&lt;p&gt;And the upside of Lua is that you don’t have to bash your head in when you battle with Vimscript’s idiosyncrasies, which more than makes up for the added verbosity during simple configuration.
Easily being able to access the Lua API of important plugins anywhere is also pleasant.&lt;/p&gt;
&lt;p&gt;You could of course mix Vimscript and Lua, but for me the consistency of having everything in the same language, using the same file structure and the same development environment makes it worth using Lua all the time.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Was-the-rewrite-worth-it&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Was-the-rewrite-worth-it&quot; class=&quot;heading-ref&quot;&gt;Was the rewrite worth it?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The million dollar question: was rewriting my entire configuration worth the time I spent doing it?&lt;/p&gt;
&lt;p&gt;If you view it from a cold efficiency point-of-view, where every minute needs to pay itself back in the future thanks to increased productivity…&lt;/p&gt;
&lt;p&gt;It’s debatable.&lt;/p&gt;
&lt;p&gt;Maybe if I don’t touch the configuration file for many years, it’ll pay off.
But I admit I spent far too much time on this for it to be considered truly productive time.&lt;/p&gt;
&lt;p&gt;To be fair, a lot of this time was spent evaluating +100 plugins to see if I wanted to use them or not, and then fiddling with them to see if I could tweak them to my liking.&lt;/p&gt;
&lt;p&gt;If all you want to do is convert your existing Vimscript config to a Lua config, it would be much faster.
And if you only need to setup LSP or Treesitter or whatever, just &lt;a href=&quot;https://github.com/catgoose/nvim&quot;&gt;look&lt;/a&gt; at &lt;a href=&quot;https://github.com/ThePrimeagen/init.lua&quot;&gt;an&lt;/a&gt; existing &lt;a href=&quot;https://github.com/LazyVim/LazyVim/tree/main&quot;&gt;config&lt;/a&gt; and you’ll get setup in no time.
You can also reference &lt;a href=&quot;https://github.com/treeman/dotfiles/tree/master/.config/nvim&quot;&gt;my config files&lt;/a&gt;, but do so on your own risk.
(Seriously, with &lt;a href=&quot;https://github.com/neovim/nvim-lspconfig&quot;&gt;lspconfig&lt;/a&gt;, &lt;a href=&quot;https://github.com/williamboman/mason.nvim&quot;&gt;mason&lt;/a&gt; and &lt;a href=&quot;https://github.com/williamboman/mason-lspconfig.nvim&quot;&gt;mason-lspconfig&lt;/a&gt; configuring LSP doesn’t take that much time.)&lt;/p&gt;
&lt;p&gt;But let’s be real here.
The joy of fiddling with configurations and tweaking small things until they’re &lt;strong&gt;just right&lt;/strong&gt; will always be worth it.&lt;/p&gt;
&lt;p&gt;I’ve spent far too much time being productive and producing value, it was about time I spent some time alone.&lt;/p&gt;
&lt;p&gt;Just me and my config.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>I beat FTL on Hard with all ships in the game</title><id>http://jonashietala.se/blog/2023/06/16/i_beat_ftl_on_hard_with_all_ships_in_the_game/index.html</id><updated>2024-06-27T07:49:29+00:00</updated><link href="https://www.jonashietala.se/blog/2023/06/16/i_beat_ftl_on_hard_with_all_ships_in_the_game" rel="alternate"/><published>2023-06-16T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;For 2023 I wanted to do something different than usual—I wanted to start playing computer games again.
So I gave myself a late Christmas gift and bought a &lt;a href=&quot;https://www.steamdeck.com/en/&quot; title=&quot;Steam Dcke: All-in-one portable PC gaming.&quot;&gt;Steam Deck&lt;/a&gt; (and like any self-serving gentleman I took care to pitch it as being for my kids) and I started loading it up with loads of emulated games and more modern ones from Steam.&lt;/p&gt;
&lt;p&gt;But then I saw that &lt;a href=&quot;https://store.steampowered.com/app/212680/FTL_Faster_Than_Light&quot; title=&quot;FTL: Faster Than Light&quot;&gt;FTL: Faster Than Light&lt;/a&gt;, one of my favorite games of all time, had gotten an “Advanced Edition”, with new systems and weapons, new ships and a brand new “Hard” difficulty. Having played the game upon release &lt;em&gt;a ton&lt;/em&gt;, but on the “Normal” difficulty, I figured I’ll try to beat it again but on Hard.&lt;/p&gt;
&lt;p&gt;And that ruined my plans, as FTL has since then been the only game I’ve been playing. It’s so good.&lt;/p&gt;
&lt;p&gt;But honestly, it’s a bit too good and addicting, so I’m glad that after 231 hours I’ve finally achieved my goal of beating Hard mode and I might be able to put it down and play some other games for a change.&lt;/p&gt;
&lt;p&gt;I didn’t start out doing this, but after a while I figured it’d be fun to take a screenshot of my victories, so future me can look back and relive these memories.&lt;/p&gt;
&lt;h1&gt;FTL is &lt;em&gt;hard&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;If you haven’t played FTL before I just want to say that the game is &lt;em&gt;hard&lt;/em&gt;. Even beating the game once on Easy is a big accomplishment as on Easy this game is more difficult than most games (and Hard is a big step up in difficulty!).&lt;/p&gt;
&lt;p&gt;But there are plenty of great resources out there if you want to get good at the game. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mike Hopley’s &lt;a href=&quot;https://ftl-ships-guide.netlify.app/&quot;&gt;FTL ships guide&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/@mikehopley&quot;&gt;YouTube channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/@neozar9481&quot;&gt;neozar&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/@crowrevell2082&quot;&gt;Crow Revell&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/@Holoshideim&quot;&gt;Holoshideim&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re an older player like me (or even if you’re not), &lt;a href=&quot;https://www.youtube.com/watch?v=8JkJ4gm3_IE&quot;&gt;this video&lt;/a&gt; on how to use scrap on Hard in FTL was a big game changer for me. The idea that you shouldn’t focus too much on “value”, but on maximizing your win probability was super helpful for me.&lt;/p&gt;
&lt;h1&gt;Some stats&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Playing time&lt;/strong&gt;: 231 hours&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Longest Hard win-streak&lt;/strong&gt;: 6 (Mantis B, Kestrel B, Fed A, Rock C, Slug A, Engi A)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bear in mind that I started from zero without any ships unlocked (I didn’t play FTL on Steam the first time around, and I didn’t find the save file). The save also got corrupted when I had beat around 2/3 of all ships, so my FTL stats are not complete:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ftl/score2.jpg&quot; /&gt;
&lt;figcaption&gt;Stats from my last save file&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It feels pretty good to have an almost 50% winrate, although it’s not really true as a bunch of those wins were me unlocking ships on Easy (and abandoning the run if I had gotten my achievements).&lt;/p&gt;
&lt;h1&gt;Some notes on ships&lt;/h1&gt;
&lt;p&gt;My focus was to just beat the game with all ships, so after I got the victory screenshot with a ship I didn’t replay it again, so my thoughts on any ship might change after future playthroughs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Most fun&lt;/strong&gt;: Stealth A, Stealth C, Slug A and Slug C.&lt;/p&gt;
&lt;p&gt;I love the efficiency of the weapons on the stealth ships and that I have to pay more attention as they don’t have shields. Slug ships are just weirdly fun (not Slug B though).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Most painful&lt;/strong&gt;: Rock A, Slug B, Federation C, Mantis B&lt;/p&gt;
&lt;p&gt;Rock A just stinks. It’s a bad ship, but it’s also not fun. Rocks are slow and missiles being consumables is not a design I like.&lt;/p&gt;
&lt;p&gt;Boarding with slugs feels super brittle and it’s not so fun to eat early game damage with Fed or Mantis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Biggest achievement&lt;/strong&gt;: Stealth B&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;almost&lt;/em&gt; won with Stealth B on my first try, but I think I needed 8 attempts or something to win with the “worst ship in the game”.&lt;/p&gt;
&lt;p&gt;Weirdly enough I never felt nearly as frustrated as I did with Rock A or Slug B.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Easiest win&lt;/strong&gt;: Lanius B&lt;/p&gt;
&lt;p&gt;I played the ship twice and won easily both times. Almost felt a bit boring after being so far ahead the whole time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Most stressful win&lt;/strong&gt;: Zoltan C&lt;/p&gt;
&lt;p&gt;Got a rough start and played a long time low on hull. But it sure feels good coming back when you think it’s all over.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ftl/zoltan_c_1hp.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;No problem, we just need to find a store.&lt;br /&gt;
Yes, I managed to turn this around to a win!&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;A memory of my victories&lt;/h1&gt;
&lt;p&gt;Unfortunately I only started taking screenshots of my victories after finally winning with Stealth B, so I had to replay around a third of the ships.&lt;/p&gt;
&lt;p&gt;And if you have a keen eye you might see the “Federation Victory (Normal)” achievement on the Kestrel. Unfortunately there’s no Hard achievement, but I did in fact &lt;a href=&quot;/images/ftl/kestrel_proof.jpg&quot;&gt;beat it with the Kestrel as well&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/kestrel_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/kestrel_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/kestrel_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/kestrel_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/kestrel_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/kestrel_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/engi_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/engi_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/engi_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/engi_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/engi_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/engi_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/fed_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/fed_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/fed_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/fed_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/fed_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/fed_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/zoltan_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/zoltan_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/zoltan_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/zoltan_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/zoltan_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/zoltan_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/stealth_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/stealth_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/stealth_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/stealth_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/stealth_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/stealth_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/rock_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/rock_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/rock_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/rock_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/rock_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/rock_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/slug_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/slug_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/slug_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/slug_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/slug_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/slug_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/ftl/mantis_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/mantis_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/mantis_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/mantis_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/mantis_c.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/mantis_c.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/ftl/crystal_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/crystal_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/crystal_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/crystal_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/ftl/lanius_a.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/lanius_a.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/ftl/lanius_b.jpg&quot;&gt;&lt;img src=&quot;/images/ftl/lanius_b.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
</content></entry><entry><title>Battling burnout</title><id>http://jonashietala.se/blog/2023/03/14/battling_burnout/index.html</id><updated>2024-07-01T05:28:09+00:00</updated><link href="https://www.jonashietala.se/blog/2023/03/14/battling_burnout" rel="alternate"/><published>2023-03-14T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;Mamma Mia! Here we go again…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;Once again, I’m finding myself trying to recover from burnout, and after about a year I’m finally feeling more like myself.&lt;/p&gt;
&lt;p&gt;Even though I’ve been here before, it’s a difficult thing to recognize and avoid, so I’m writing this to maybe help you or my future self.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Is-it-burnout-depression-or-both&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Is-it-burnout-depression-or-both&quot; class=&quot;heading-ref&quot;&gt;Is it burnout, depression or both?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I find it’s difficult to pinpoint exactly what I’ve been through.
The first doctor I met diagnosed me as suffering from “extreme stress”, without mentioning depression.
The psychologist I met next didn’t think I had any signs of depression either, but the one after that (that I worked with for a few months with KBT) thought I showed clear signs of depression as well as being burnt-out.&lt;/p&gt;
&lt;section id=&quot;Signs-of-burnout&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Signs-of-burnout&quot; class=&quot;heading-ref&quot;&gt;Signs of burnout&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Doing a little research of my own, I clearly displayed the three clusters of burnout:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Emotional and physical exhaustion
&lt;/li&gt;
&lt;li&gt;
Cynicism
&lt;/li&gt;
&lt;li&gt;
Lower productivity
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This to an extent that it effected my work- and personal life, but not so much that I couldn’t get out of bed.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Signs-of-depression&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Signs-of-depression&quot; class=&quot;heading-ref&quot;&gt;Signs of depression&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I don’t recognize all the symptoms of depression, but I did display some of them:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Negative outlook of the future
&lt;/li&gt;
&lt;li&gt;
Depressed mood
&lt;/li&gt;
&lt;li&gt;
Diminished pleasure
&lt;/li&gt;
&lt;li&gt;
Easily agitated
&lt;/li&gt;
&lt;li&gt;
Gained weight
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These weren’t &lt;strong&gt;that&lt;/strong&gt; serious, and I never had the really serious signs like suicidal thoughts, but it did feel like the symptoms were getting worse and I’m sure if I didn’t do anything about the underlying causes then it would eventually spiral out of control.&lt;/p&gt;
&lt;p&gt;Still, I consider burnout to be the primary issue, with the depression following along like an added bonus.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;No-apparent-reason&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#No-apparent-reason&quot; class=&quot;heading-ref&quot;&gt;No apparent reason&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve had large difficulties to accept the burnout because if I try to distance myself from the problem and look at it objectively from a distance, it doesn’t make sense that I would become a victim.
I have all these great benefits that I’ve worked at a long time trying to obtain:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A great family, with three amazing kids that I love with all my heart.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Low stress from work.&lt;/p&gt;
&lt;p&gt;It seems if you read about burnout online, everything seems to circle around too much stress from work. Either too long hours, too many responsibilities, bad bosses, bad co-workers, too tight deadlines or a combination of it all is always the culprit.&lt;/p&gt;
&lt;p&gt;But I just can’t relate to any of that.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Few and flexible working hours.&lt;/p&gt;
&lt;p&gt;Apart from having flexible working hours, so as long as I’m there for some meetings I can basically decide when I should work.
It’s super nice to be able to take an extra hour of sleep if I woke up too early with the kids, or take an hour to do some weight lifting.&lt;/p&gt;
&lt;p&gt;I also don’t work too many hours. I’ve been working 80% (32h / week) since more than a year back, and I’m good at not exceeding that.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I work remotely.&lt;/p&gt;
&lt;p&gt;Barring a handful of yearly trips, which I’ve been wanting to do because of social reasons, I’ve been working remotely since 4 years now.
And there are some massive benefits to it, like being able to work without disturbance from my home office, using my home gym that’s right next to my office and avoiding a commute.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I’m able to work professionally in Rust.&lt;/p&gt;
&lt;p&gt;Rust is a favorite language of many programmers, but finding a non-crypto Rust job is very difficult.
But here I am with a Rust job.
(My employer started some projects in Rust and I started working on those.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Good salary.&lt;/p&gt;
&lt;p&gt;While I could absolutely push my salary higher if I was motivated enough to switch jobs or start my own consulting business, I earn more than enough for my current needs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It feels like the other stories about burnout always have this obvious reason for people hitting the wall (like working 80+ hours a week), but I just can’t find an easy explanation for me.&lt;/p&gt;
&lt;p&gt;— &lt;em&gt;Maybe it’s just too difficult to realize it yourself when it’s all happening?
I thought I was getting over it, but maybe I’m still in it…?&lt;/em&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Red-flags&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Red-flags&quot; class=&quot;heading-ref&quot;&gt;Red flags&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While it was (and is) difficult for me to see the cause, I did notice some of the big red flags signalling that I was getting, or already was, burnt-out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Things weren’t fun&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Even my favorite hobbies lost their appeal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;I became more cynical&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;— &lt;em&gt;It’s not worth doing this…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;— &lt;em&gt;It makes no difference…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;— &lt;em&gt;This won’t help anyone…&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Lack of energy&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Despite the previous point, I still wanted to do lots of things, but I didn’t have the energy to do them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Difficulty falling asleep&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Even though I was constantly tired, it got harder and harder to fall asleep.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;More easily irritated&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Getting annoyed and even angry at trivial things.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;I didn’t make any progress on my side projects&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mind you, programming in some way has been my main hobby for over a decade.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Work performance dropped&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I didn’t get any comments from co-workers, but I felt that I wasn’t nearly as productive as I was 3-6 months previously, let alone a year or two ago.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When I list them like this it might seem like it should be easy to notice them, but it’s really not.
They creep up on you and it’s hard to see them when you’re in the middle of it yourself.
(It’s easier to see faults in others after all.)&lt;/p&gt;
&lt;p&gt;The first time I thought that maybe I’m becoming burnt-out is when I was watching some fantastic TV-series (&lt;a href=&quot;https://www.imdb.com/title/tt3032476 &amp;quot;Better Call Saul&amp;quot;&quot;&gt;Better Call Saul&lt;/a&gt; and &lt;a href=&quot;https://www.imdb.com/title/tt6468322 &amp;quot;Money Heist&amp;quot;&quot;&gt;Money Heist&lt;/a&gt;).
They were so good that I often thought about them—even dreamt of them—and I couldn’t wait to see the next episode.
Yet after the amazing Better Call Saul episode with Nacho (season 6 episode 3, you know which one if you’ve seen the show) I just couldn’t make myself to see the next episode.&lt;/p&gt;
&lt;p&gt;It’s a weird feeling when you &lt;strong&gt;know&lt;/strong&gt; you love something, but you feel completely drained of joy when you think about doing it, but I can’t describe it any other way.&lt;/p&gt;
&lt;p&gt;This can be difficult to recognize, but I did remember the same feeling of joylessness from my previous burnout episode around 8 years ago.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Seeking-help&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Seeking-help&quot; class=&quot;heading-ref&quot;&gt;Seeking help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;But even if I noticed some of the red flags, and I did try to make some small changes, the real wake-up call was when I was flying home from a work trip and I got this extreme headache.
It was more extreme than I had ever had (and I’ve had occasional migraine attacks for years), so much that I thought I was getting a stroke or something.
While the pain dissipated in a few minutes, I felt sick the whole day after.&lt;/p&gt;
&lt;p&gt;I didn’t have a stroke—it was declared as “only” a migraine attack—but it was clear I had to take it seriously.
So I did what everyone recommends: I sought professional help.&lt;/p&gt;
&lt;p&gt;And I’m glad I did, because without it I probably would’ve crashed &lt;strong&gt;much&lt;/strong&gt; harder.&lt;/p&gt;
&lt;p&gt;The company I work for took it seriously and was incredibly helpful and were very supportive throughout the whole process.
They reduced my workload, made it clear that that I could take as much time off as needed and importantly they never made me feel guilty.&lt;/p&gt;
&lt;p&gt;Admitting that I had a problem was a difficult thing.
I really wanted to hide that I went on sick leave from my partner—a very clear vote for fleeing over fighting.
Maybe if I didn’t tell anyone I could continue fooling myself that everything was fine?&lt;/p&gt;
&lt;p&gt;But I didn’t hide it, and she was also very supportive.
How could I ever have thought otherwise?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;What-was-the-actual-cause&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#What-was-the-actual-cause&quot; class=&quot;heading-ref&quot;&gt;What was the actual cause?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the root cause wasn’t external stress, such as work pressure, now I think it was &lt;strong&gt;internal&lt;/strong&gt; stress coming from me pressuring myself.&lt;/p&gt;
&lt;p&gt;One big part of it is all my different projects I’ve got going.
Having projects to work on has always been a source of enjoyment and pride.
It’s not that I seek fame or recognition, it’s the simple and wonderful feeling of accomplishment and satisfaction of creating something that drives me.&lt;/p&gt;
&lt;p&gt;Unfortunately, I have too many large and unfinished projects that started to stress me out because they weren’t finished, and as my productivity slowed down they stressed me out even more.&lt;/p&gt;
&lt;p&gt;Here are of some of my ongoing software development projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Finish my book: &lt;a href=&quot;https://whycryptocurrencies.com/ &amp;quot;Why Cryptocurrencies?: What they are, what they do, and why they matter&amp;quot;&quot;&gt;Why Cryptocurrencies?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I &lt;strong&gt;only&lt;/strong&gt; need to restyle the e-book and allow people to buy it from my site.
The physical book has been done over a year ago.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Release the first version of &lt;a href=&quot;https://github.com/bitpal &amp;quot;BitPal: A self-hosted cryptocurrency payment processor&amp;quot;&quot;&gt;BitPal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wanted to allow people to buy my book about crypto with crypto, so I started working on my own self-hosted solution.&lt;/p&gt;
&lt;p&gt;It’s &lt;strong&gt;so close&lt;/strong&gt; to being “done”; I’ve already done 90% so it’s only the last 90% left now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finish my git implementation in Rust&lt;/p&gt;
&lt;p&gt;I’ve worked through one-third of &lt;a href=&quot;https://www.goodreads.com/book/show/44128595-building-git &amp;quot;Building Git&amp;quot;&quot;&gt;Building Git&lt;/a&gt; (but with Rust instead of Ruby), and I would really like to continue with the fun branching and rebasing stuff.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rewrite the site for our grappling club&lt;/p&gt;
&lt;p&gt;I’d like to have member account, track billing and have some notification system for when training sessions are canceled.
Simple stuff.
If we ignore the idea of tracking attendance and topics of each session, so we can plan an adaptive spaced repetition curriculum to optimize learning.&lt;/p&gt;
&lt;p&gt;And yet, I’m stuck on getting the styling and layout on the page right.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While creating things is important to me, something else that’s even more important to me—and part of my identity—is improving my skills.
It’s not about reaching some goal, but I relish the feeling of learning something new or being able to do something I previously could not.&lt;/p&gt;
&lt;p&gt;Here’s a few things that I’m working on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Programming skills&lt;/p&gt;
&lt;p&gt;Learning new languages, tools and new ways of solving problems in a faster or simpler way.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Strength training&lt;/p&gt;
&lt;p&gt;I used to think that squatting is easy.
But the more I learn about it, the harder it seems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Grappling&lt;/p&gt;
&lt;p&gt;I don’t train that much (1-2 times a week), but still the learning and research continues with tons of hours of instructionals available.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Memory training&lt;/p&gt;
&lt;p&gt;The main goal was to supercharge language learning by making it easier to learn lots of new words.
Honestly though, it was years since I last worked on it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It shouldn’t be like this, but I feel sad or bad when I’m not trying to improve at something.&lt;/p&gt;
&lt;p&gt;And what stresses me out even more are the things I &lt;strong&gt;&lt;strong&gt;”should”&lt;/strong&gt;&lt;/strong&gt; be doing, but haven’t started yet. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;https://www.gamedeveloper.com/design/how-to-make-a-roguelike &amp;quot;How to Make a Roguelike&amp;quot;&quot;&gt;Make a roguelike&lt;/a&gt; in Rust
&lt;/li&gt;
&lt;li&gt;
Create a board game
&lt;/li&gt;
&lt;li&gt;
Learn Korean, Japanese, Finnish…
&lt;/li&gt;
&lt;li&gt;
Listen to hundreds of hours in my podcast app (not including audiobooks, I use Audible for those)
&lt;/li&gt;
&lt;li&gt;
Finish dozens of programming books on my to-read list
&lt;/li&gt;
&lt;li&gt;
Finish dozens of fiction books on my to-read list
&lt;/li&gt;
&lt;li&gt;
Figure out a product I want to develop and sell
&lt;/li&gt;
&lt;li&gt;
etc …
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these items I list aren’t that stressful by themselves, it’s the combination of many small stressors that over time has caused me an awful amount of stress.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Things-that-helped-me&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Things-that-helped-me&quot; class=&quot;heading-ref&quot;&gt;Things that helped me&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While I did receive help from work, my family and from professionals, it’s important to realize that in the end you’re the only one who can solve your problems. So here’s a list of things that I did that I think were helpful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Be kind towards myself&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I try to reduce the expectations on myself, and I try not to beat myself up if I don’t do everything as quickly as I’d like to.&lt;/p&gt;
&lt;p&gt;But honestly, it’s really hard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Go outside and walk&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I didn’t like it when they told me I should go out and just walk, but honestly it was super helpful.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Physical exercise&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Exercise has really helped me every time I’ve been feeling down, and this time is no different.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Do things I used to enjoy&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It’s important to break the downward spiral, and forcing yourself to do the things that you used to enjoy—that you intellectually know you still enjoy—is the best way that I’ve found.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Rest&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When your energy is low you need to stop and recharge.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;The-only-thing-that-really-helped-me&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-only-thing-that-really-helped-me&quot; class=&quot;heading-ref&quot;&gt;The only thing that really helped me&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While all of the above were helpful in the long run, the only thing that &lt;strong&gt;really&lt;/strong&gt; helped me break the further decline was &lt;strong&gt;&lt;strong&gt;taking time off&lt;/strong&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If started with a 100% sick leave for 3 weeks, followed by a 50% sick leave for 4 weeks and then a 7 weeks long summer vacation.
The point was to focus on my recovery, so of course I was forbidden from working on my projects and endeavors too.&lt;/p&gt;
&lt;p&gt;I’m convinced that even if I did everything else right (walking, trying to enjoy life etc) I wouldn’t have managed it without this break. I’ve read the opinion that the &lt;strong&gt;only&lt;/strong&gt; thing that can cure a bad burnout is removing yourself from the stressful environment. I’m not sure I’d go that far, but it sure felt that way for me this time.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Are-you-ever-cured&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Are-you-ever-cured&quot; class=&quot;heading-ref&quot;&gt;Are you ever cured?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It’s now been a little over a year since my big wake-up call on the flight home, and it’s only now that I feel I’m myself again. I’m finally making progress on my projects again, and I can do &lt;a href=&quot;https://www.lifehack.org/849518/deep-work-rules&quot;&gt;deep work&lt;/a&gt; to a satisfactory degree again.&lt;/p&gt;
&lt;p&gt;The healing process has been slow—much slower than I could’ve thought.
Even though it took around a year last time to recover too, a year is a damn long time.
A lesson I’ve learned (or having to re-learn) is that doing everything you can to avoid a burnout will pay off in the long run.&lt;/p&gt;
&lt;p&gt;But the worst part is: will you ever truly get rid of it?
Or is the burnout forever etched into your brain, just waiting for an opportunity to make your life miserable again?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Most people, including myself, keep repeating the same mistakes
&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;William Shatner
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/section&gt;
</content></entry><entry><title>2022 in review</title><id>http://jonashietala.se/blog/2023/02/15/2022_in_review/index.html</id><updated>2024-04-29T06:23:18+00:00</updated><link href="https://www.jonashietala.se/blog/2023/02/15/2022_in_review" rel="alternate"/><published>2023-02-15T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A bit late, but it’s time for my &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly reviews&quot;&gt;yearly review&lt;/a&gt;. It’s something I like doing for myself and it’s nice to see that despite a tough year I’ve done some good things.&lt;/p&gt;
&lt;h1&gt;2022 Non-Geek Achievements&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We got our third child!&lt;/p&gt;
&lt;p&gt;This time we got a girl to complement our two boys, and I love them all more than anything. I wouldn’t trade them for the world.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote &lt;a href=&quot;/archive&quot; title=&quot;My archive&quot;&gt;4 blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2022 Geek Achievements&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit/&quot; title=&quot;Rewriting my blog in Rust for fun and profit&quot;&gt;Rewrote the blog in Rust&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote more Rust (thanks to my job).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some Typescript (again due to my job).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Started home automation with &lt;a href=&quot;https://www.home-assistant.io/&quot; title=&quot;Home Assistant&quot;&gt;Home Assistant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It started with us installing solar panels, and I wanted to get some pretty graphs from it to see how it performed.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/solar.png&quot; /&gt;
&lt;figcaption&gt;Pretty graphs in Grafana. Even though it’s cold and snowy, we still produce some energy.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;But it all went downhill from there…&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/zigbee.png&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;The core of my zigbee network connecting some lamps, plugs, switches and controls in our home.
There are now 52 connected devices, and it will continue to grow.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There are still &lt;em&gt;tons&lt;/em&gt; of things I want to implement, fix and play around with.
I think it’s best not to think of smart-home as some sort of money or time saver, but more as a hobby that might have some positive effects.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Books I remember&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.goodreads.com/series/43531-gentleman-bastard&quot; title=&quot;Gentlemen Bastards Series&quot;&gt;&lt;em&gt;Gentlemen Bastards Series&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Disgustingly evil and I’ve got another book to eternally wait for (like the now 12 year wait for &lt;em&gt;Winds of Winter&lt;/em&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://charlesduhigg.com/the-power-of-habit/&quot; title=&quot;The Power of Habit&quot;&gt;&lt;em&gt;The Power of Habit&lt;/em&gt;&lt;/a&gt; and &lt;a href=&quot;https://jamesclear.com/atomic-habits&quot; title=&quot;Atomic Habits&quot;&gt;&lt;em&gt;Atomic Habits&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After reading these books I’m convinced that habits is the most powerful tool we humans have, and I need to be more conscious about them going forward. The Power of Habit is the more inspirational book, while Atomic Habits gives the blueprint of how to establish the habits you want.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Boardgames I remember&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/162886/spirit-island&quot; title=&quot;Spirit Island&quot;&gt;Spirit Island&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I’ve never played a boardgame solo before, as I always identified boardgames with social interactions.
But there’s really no difference between playing a boardgame alone, versus playing a computer game alone.
And I had an extremely good time playing Spirit Island.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/341169/great-western-trail-second-edition&quot; title=&quot;Great Western Trail 2nd Edition&quot;&gt;Great Western Trail&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you put me on the spot to name my current #1 boardgame, I’d have to give it to Great Western Trail.
Such an amazingly well designed game.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/231733/obsession&quot; title=&quot;Obsession&quot;&gt;Obsession&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Obsession is quite an unique game, and it might be the game I’m most glad of having in my collection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/272739/clinic-deluxe-edition&quot; title=&quot;Clinic Deluxe Edition&quot;&gt;Clinic Deluxe Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A very thematic and chunky game about managing a hospital. I haven’t played it a lot, but I can’t wait to play it again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/124742/android-netrunner&quot; title=&quot;Android: Netrunner&quot;&gt;Netrunner&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Many years ago I used to play a ton of Netrunner and went to tournaments and stuff, and to this day Netrunner has given me the best boardgaming memories of all time.&lt;/p&gt;
&lt;p&gt;Unfortunately it became a bit too much and I got burnt out from &lt;a href=&quot;https://www.reddit.com/r/Netrunner/comments/a0pz32/mumbad_cycle_is_usually_considered_the_lowpoint/eajoe5t/&quot; title=&quot;Mumbad Cycle was the low-point of A:NR&quot;&gt;the Mumbad Cycle meta&lt;/a&gt;, so I took a break to focus on other things, and then Fantasy Flight stopped developing the game. A sad ending to a great game.&lt;/p&gt;
&lt;p&gt;Or so I thought. The fan organization &lt;a href=&quot;https://nullsignal.games/&quot; title=&quot;Null Signal Games&quot;&gt;Null Signal Games&lt;/a&gt; (previously Nisei) has continued to support the game and has continued to release new cards for Netrunner, keeping the game alive and well.&lt;/p&gt;
&lt;p&gt;This is super exciting, and in many ways their releases are even better than Fantasy Flights (less useless cards, more coherent releases and less game-breaking interactions). So I bought all the new cards (I kind of regret selling my complete collection a couple of years ago) and I hope I get to play with them sometime.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/329082/radlands&quot; title=&quot;Radlands&quot;&gt;Radlands&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A quick and fantastic two player card game. If a lifestyle game like Netrunner is too much, Radlands is the perfect alternative.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/822/carcassonne&quot; title=&quot;Carcassonne&quot;&gt;Carcassonne&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/300010/dragomino&quot; title=&quot;Dragomino&quot;&gt;Dragomino&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To my eternal joy, my oldest kid has been enjoying gaming more and more, and both me and him have been loving Carcassonne and Dragomino.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2022 Misadventures&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Got depressed and burnt-out.&lt;/p&gt;
&lt;p&gt;I’ve been meaning to write a post about this, but I haven’t had the energy for it yet.
I think it’s enough to say that this defined 2022 for me, and even though I was on sick leave for “only” two months, I still haven’t fully recovered my energy and productivity despite the first serious symptoms revealing themselves over a year ago.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Plans for 2023&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Spend more time with my kids.&lt;/p&gt;
&lt;p&gt;After all, there is nothing more important.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reduce the boardgame list-of-shame that (I think) consists of 12 games that I own but have never played.&lt;/p&gt;
&lt;p&gt;A more daunting task than it might seem as it’s been very hard to get time for gaming, and I’m waiting for something like 10+ crowdfunding games to arrive in 2023. Oops.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More focus on health, both psychological and physical.&lt;/p&gt;
&lt;p&gt;After being sick you realize how important your health is, which is something I’ve gotten new appreciation for.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Establish &lt;a href=&quot;https://www.lifehack.org/849518/deep-work-rules&quot; title=&quot;Deep Work&quot;&gt;Deep Work&lt;/a&gt; as my &lt;a href=&quot;https://jamesclear.com/keystone-habits&quot; title=&quot;Keystone Habits&quot;&gt;keystone habit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After becoming convinced that controlling your habits is the best thing since sliced bread, I’ve decided that the big productivity focus of 2023 is focused on habits, and specifically creating the habit of Deep Work (or the hyper productive flow state that hopefully all programmers recognize).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finish the digital version of &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;my book&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The plan was to finish it last year so I could move on to other projects, but if I don’t finish it now it might never be done. Therefore I’ll dedicate the spring to finally finalize it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Play games instead of doom scrolling on the phone or lazily watch TV.&lt;/p&gt;
&lt;p&gt;As I’m writing this I’ve had my &lt;a href=&quot;https://www.steamdeck.com/en/&quot; title=&quot;Steam Deck&quot;&gt;Steam Deck&lt;/a&gt; for around a month, and it’s absolutely amazing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>The current T-34 keyboard layout</title><id>http://jonashietala.se/blog/2022/09/06/the_current_t-34_keyboard_layout/index.html</id><updated>2026-04-27T10:16:40+00:00</updated><link href="https://www.jonashietala.se/blog/2022/09/06/the_current_t-34_keyboard_layout" rel="alternate"/><published>2022-09-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I’ve been documenting my own keyboard layout &lt;a href=&quot;/series/t-34/&quot; title=&quot;The T-34 keyboard layout&quot;&gt;in a series&lt;/a&gt; for a while now. But as the layout is constantly changing it’s been difficult to piece together how the layout currently looks like, so this post tries to show how the layout looks right now in it’s entirety.&lt;/p&gt;
&lt;p&gt;If you want to read about the background and philosophy about the layout, please see the &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/&quot; title=&quot;T-34 first post&quot;&gt;original T-34 post&lt;/a&gt;, and to see it’s evolution please refer to the &lt;a href=&quot;/series/t-34/&quot; title=&quot;The T-34 keyboard layout&quot;&gt;T-34 series&lt;/a&gt;. The layout is implemented using &lt;a href=&quot;https://docs.qmk.fm/&quot; title=&quot;QMK&quot;&gt;QMK&lt;/a&gt; and the &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/ferris/keymaps/treeman&quot; title=&quot;QMK source code&quot;&gt;code is on Codeberg&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The layout is made for a small 34 key keyboard, I use the &lt;a href=&quot;https://github.com/pierrechevalier83/ferris&quot; title=&quot;The Ferris keyboard&quot;&gt;Ferris&lt;/a&gt; with flat choc keycaps to easily press &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;Legend&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Legend&quot; class=&quot;heading-ref&quot;&gt;Legend&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/legend.svg&quot;&gt;
&lt;figcaption&gt;Legend
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Layers&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Layers&quot; class=&quot;heading-ref&quot;&gt;Layers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.qmk.fm/#/feature_layers&quot; title=&quot;QMK layers&quot;&gt;Layers&lt;/a&gt; are the meat and potatoes of any layout for a smaller keyboard, and mine is no different.&lt;/p&gt;
&lt;section id=&quot;Base&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Base&quot; class=&quot;heading-ref&quot;&gt;Base&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_BASE.svg&quot;&gt;
&lt;figcaption&gt;Base layer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;a href=&quot;#Repeat-key&quot;&gt;repeat key&lt;/a&gt; is used to output the last pressed key. I shift keys using &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot; title=&quot;QMK auto shift&quot;&gt;auto shift&lt;/a&gt; (see &lt;a href=&quot;#Long-press&quot;&gt;long press&lt;/a&gt;) and &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt;. The letters &lt;code&gt;Z&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt;, together with a bunch of other keys, are on &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Swedish-overlay&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Swedish-overlay&quot; class=&quot;heading-ref&quot;&gt;Swedish overlay&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_SWE.svg&quot;&gt;
&lt;figcaption&gt;Swedish overlay.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;When I want to write Swedish I activate this layer that replaces &lt;code&gt;()_&lt;/code&gt; with &lt;code&gt;åäö&lt;/code&gt;, or I use &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; from any layer.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Navigation-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Navigation-layer&quot; class=&quot;heading-ref&quot;&gt;Navigation layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_NAV.svg&quot;&gt;
&lt;figcaption&gt;Navigation layer.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;Gui-W&lt;/code&gt;, &lt;code&gt;Gui-E&lt;/code&gt; and &lt;code&gt;Gui-R&lt;/code&gt; are used to switch between monitors and &lt;code&gt;Gui-J&lt;/code&gt;/&lt;code&gt;Gui-K&lt;/code&gt; to switch windows in &lt;a href=&quot;https://xmonad.org/&quot; title=&quot;Xmonad&quot;&gt;xmonad&lt;/a&gt;. &lt;code&gt;Ctrl&lt;/code&gt; + arrow is used to switch windows in Vim. Tabbing is for switching tabs in Firefox.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Workspace-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Workspace-layer&quot; class=&quot;heading-ref&quot;&gt;Workspace layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_WNAV.svg&quot;&gt;
&lt;figcaption&gt;Workspace layer. All keys have an implicit &lt;code&gt;Gui&lt;/code&gt; modifier.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This is used for all window and workspace management in &lt;a href=&quot;https://xmonad.org/&quot; title=&quot;Xmonad&quot;&gt;xmonad&lt;/a&gt;. Some common operations are also on the &lt;a href=&quot;#Navigation-layer&quot;&gt;navigation layer&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Windows-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Windows-layer&quot; class=&quot;heading-ref&quot;&gt;Windows layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_WIN.svg&quot;&gt;
&lt;figcaption&gt;Windows layer. All keys have an implicit &lt;code&gt;Alt&lt;/code&gt; modifier.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This is purely to enable window switching using &lt;code&gt;Alt-Tab&lt;/code&gt; and &lt;code&gt;Ctrl-Alt-Tab&lt;/code&gt;, without releasing &lt;code&gt;Alt&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Numbers&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Numbers&quot; class=&quot;heading-ref&quot;&gt;Numbers&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_NUM.svg&quot;&gt;
&lt;figcaption&gt;Numbers. The darkened keys turn off &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;While I can activate the number layer persistently (using &lt;a href=&quot;#Leader-sequences&quot;&gt;leader sequences&lt;/a&gt;) I typically use &lt;a href=&quot;#Numbers-and-symbols&quot; title=&quot;Numbers and symbols&quot;&gt;combos&lt;/a&gt; for single digitis (like &lt;code&gt;0&lt;/code&gt;), or &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; for larger numbers (like &lt;code&gt;1984&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; makes the number layer smart, so it will deactivate when certain keys are pressed (colored dark gray in the image). It’s used to type numbers in text or code and for relative movement in Vim, where &lt;code&gt;17J&lt;/code&gt; would move 17 lines down and then turn off the number layer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@u&lt;/code&gt; is there to easily activate macros in Vim. For example &lt;code&gt;7@u&lt;/code&gt; in the number layer would run the &lt;code&gt;u&lt;/code&gt; macro 7 times and then turn off &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Function-keys&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Function-keys&quot; class=&quot;heading-ref&quot;&gt;Function keys&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_FUN.svg&quot;&gt;
&lt;figcaption&gt;Function keys.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Symbols&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Symbols&quot; class=&quot;heading-ref&quot;&gt;Symbols&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_SYM.svg&quot;&gt;
&lt;figcaption&gt;Symbols.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Similar to the numbers layer, there are &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; that are used to output standalone symbols. The &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; follow the layout of the symbols layer, and combos with same-side thumb. So &lt;code&gt;Space&lt;/code&gt; + left-hand key or &lt;code&gt;E&lt;/code&gt; + right-hand key outputs a symbol, regardless of what layers are activated.&lt;/p&gt;
&lt;p&gt;Some common symbol sequences, like &lt;code&gt;-&amp;gt;&lt;/code&gt;, exists as &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; and others, like &lt;code&gt; != &lt;/code&gt;, as &lt;a href=&quot;#Long-press&quot;&gt;long press&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;One-handed-Shortcuts&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#One-handed-Shortcuts&quot; class=&quot;heading-ref&quot;&gt;One-handed Shortcuts&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_SHRT.svg&quot;&gt;
&lt;figcaption&gt;Shortcuts.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;To give access to common QWERTY shortcuts using the left hand, for programs where I have my right hand on the mouse/trackball. (&lt;a href=&quot;#Long-press&quot;&gt;Long press&lt;/a&gt; still shifts them.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Special-symbols&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Special-symbols&quot; class=&quot;heading-ref&quot;&gt;Special symbols&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_SPEC.svg&quot;&gt;
&lt;figcaption&gt;Specials (with ←↓↑→ symbols, not arrow keys).
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Some of these are &lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_key&quot; title=&quot;Dead keys&quot;&gt;dead keys&lt;/a&gt;, to add diacritic to any letter. To get &lt;code&gt;é&lt;/code&gt; I do &lt;code&gt;´&lt;/code&gt; then &lt;code&gt;e&lt;/code&gt;, and the operating system will merge them together.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Modifiers&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Modifiers&quot; class=&quot;heading-ref&quot;&gt;Modifiers&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/_MODS.svg&quot;&gt;
&lt;figcaption&gt;Modifiers.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I typically use &lt;a href=&quot;#Long-press&quot;&gt;long press&lt;/a&gt; for shift and &lt;a href=&quot;#Combos&quot;&gt;combos&lt;/a&gt; for other modifiers, this layer is a fallback for when those aren’t enough.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Combos&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Combos&quot; class=&quot;heading-ref&quot;&gt;Combos&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.qmk.fm/#/feature_combo&quot; title=&quot;QMK combos&quot;&gt;Combos&lt;/a&gt; is another fantastic tool that I (ab)use a lot. Simply put it allows you to press multiple keys at once and acts as an additional key—very useful for smaller layouts.&lt;/p&gt;
&lt;p&gt;Note that combos are layer independent, and work the same regardless of what layers are activated. The base layer is shown in the graphics for reference.&lt;/p&gt;
&lt;section id=&quot;Neighbour-combos&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Neighbour-combos&quot; class=&quot;heading-ref&quot;&gt;Neighbour combos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These combos are made by keys next to each other, either horizontally (pressed with two fingers) or vertically (pressed with one finger in the middle of two keys).&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/neighbour_combos.svg&quot;&gt;
&lt;figcaption&gt;2-key neighboring combos.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
Some combos have a separate hold behaviour; for instance holding &lt;code&gt;Escape&lt;/code&gt; activates the &lt;a href=&quot;#Symbols&quot;&gt;symbols layer&lt;/a&gt;, allowing me to output &lt;code&gt;[]&lt;/code&gt; easily.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vsplit&lt;/code&gt; splits a window vertically in Vim and &lt;code&gt;hsplit&lt;/code&gt; splits it horizontally, and &lt;code&gt;Close Window&lt;/code&gt; closes a window in Vim (&lt;code&gt;&amp;lt;C-w&amp;gt;q&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Clear&lt;/code&gt; resets all states; sets the &lt;a href=&quot;#Base&quot;&gt;base&lt;/a&gt; layer, releases modifiers, stops &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt; and &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt;, and clears other persistent states.
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/mid_triple_combos.svg&quot;&gt;
&lt;figcaption&gt;3-key horizontal combos.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SWE&lt;/code&gt; activates the &lt;a href=&quot;#Swedish-overlay&quot;&gt;Swedish layer&lt;/a&gt;, and if prefixed with &lt;code&gt;()_&lt;/code&gt; it will replace that with &lt;code&gt;åäö&lt;/code&gt; and vice versa. So for example if I typed &lt;code&gt;hall(&lt;/code&gt; I would press &lt;code&gt;SWE&lt;/code&gt; to get &lt;code&gt;hallå&lt;/code&gt;, with the Swedish layer activated.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl W&lt;/code&gt; is used to close tabs in Firefox.
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/save_vim.svg&quot;&gt;
&lt;figcaption&gt;A 4-key horizontal combo.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Save Vim&lt;/code&gt; is a 4-key combo that saves the buffer in Vim.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Split-combos&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Split-combos&quot; class=&quot;heading-ref&quot;&gt;Split combos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These split combos uses the ring and index finger.&lt;/p&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/quotes.svg&quot;&gt;
&lt;figcaption&gt;Combos for the quotes &lt;code&gt;&quot;&lt;/code&gt; and &lt;code&gt;&apos;&lt;/code&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/angled.svg&quot;&gt;
&lt;figcaption&gt;Combos don’t have to be on the same row, these angled combos are fairly comfortable.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/split_lower.svg&quot;&gt;
&lt;figcaption&gt;One-shot &lt;code&gt;Alt&lt;/code&gt; and the &lt;a href=&quot;#Leader-sequences&quot;&gt;Leader key&lt;/a&gt;.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Combos-over-keyboard-halfs&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Combos-over-keyboard-halfs&quot; class=&quot;heading-ref&quot;&gt;Combos over keyboard halfs&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/smart_layers.svg&quot;&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
Tapping &lt;code&gt;T&lt;/code&gt; + &lt;code&gt;A&lt;/code&gt; once activates &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt;, tapping again makes it persistent (&lt;code&gt;CAPS LOCK&lt;/code&gt;), and a third tap to deactivate &lt;code&gt;CAPS LOCK&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Tapping &lt;code&gt;Space&lt;/code&gt; + &lt;code&gt;E&lt;/code&gt; activates &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt; and tapping them again activates the &lt;a href=&quot;#Numbers&quot;&gt;number layer&lt;/a&gt; persistently.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;#Repeat-key&quot;&gt;repeat key&lt;/a&gt; works with the above, making them easier to double-tap.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Numbers-and-symbols&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Numbers-and-symbols&quot; class=&quot;heading-ref&quot;&gt;Numbers and symbols&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/MT_SPC.svg&quot;&gt;
&lt;figcaption&gt;Combos using &lt;code&gt;Space&lt;/code&gt; and another key.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img embed=&quot;true&quot; alt=&quot;&quot; src=&quot;/images/t-34-layout/SE_E.svg&quot;&gt;
&lt;figcaption&gt;Combos using &lt;code&gt;E&lt;/code&gt; and another key.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Combos with a thumb key is used for digits or standalone symbols, with the logic of &lt;code&gt;same-side thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt; = &lt;code&gt;symbol&lt;/code&gt; and &lt;code&gt;opposite-side thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt; = &lt;code&gt;digit&lt;/code&gt;. The placements follow the &lt;a href=&quot;#Numbers&quot;&gt;numbers&lt;/a&gt;, &lt;a href=&quot;#Symbols&quot;&gt;symbols&lt;/a&gt; and &lt;a href=&quot;#Swedish-overlay&quot;&gt;Swedish&lt;/a&gt; layers. Both thumbs activates &lt;a href=&quot;#NUMWORD&quot;&gt;NUMWORD&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Long-press&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Long-press&quot; class=&quot;heading-ref&quot;&gt;Long press&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most keys have a different behaviour when tapped compared to a long press. Most commonly I use this to produce shifted keys (called &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot; title=&quot;QMK auto shift&quot;&gt;auto shift&lt;/a&gt;). So to get &lt;code&gt;A&lt;/code&gt; I press and hold &lt;code&gt;a&lt;/code&gt; until it turns up.&lt;/p&gt;
&lt;p&gt;There are a bunch of special cases as well (mostly on top of [combos]):&lt;/p&gt;
&lt;table class=&quot;center&quot;&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Tap&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Long press&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;_&lt;/code&gt; &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;\&lt;/code&gt; &lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Double, e.g &lt;code&gt;__&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;&quot;&lt;/code&gt; &lt;code&gt;&apos;&lt;/code&gt; &lt;code&gt;=&lt;/code&gt; &lt;code&gt;`&lt;/code&gt; &lt;code&gt;0&lt;/code&gt; &lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Triple, e.g &lt;code&gt;&quot;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;|&lt;/code&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Double with spaces, e.g &lt;code&gt;||&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt; != &lt;/code&gt; (with spaces)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;{:?}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;{:#?}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;%{}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;(&lt;/code&gt; &lt;code&gt;[&lt;/code&gt; &lt;code&gt;{&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Close and move cursor between&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;@u&lt;/code&gt; (paired with &lt;code&gt;qu&lt;/code&gt; combo for Vim macro execution)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section id=&quot;Leader-sequences&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Leader-sequences&quot; class=&quot;heading-ref&quot;&gt;Leader sequences&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I use the combo &lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt; as the &lt;a href=&quot;https://docs.qmk.fm/#/feature_leader_key&quot; title=&quot;QMK leader key&quot;&gt;leader key&lt;/a&gt;. This will wait for a sequence of key presses (in contrast to combos where keys must be pressed at the same time). This is used with mnemonics for rarely used outputs:&lt;/p&gt;
&lt;table class=&quot;center&quot;&gt;
&lt;tr&gt;
&lt;th&gt;Leader sequence&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/strong&gt;aps lock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/strong&gt;oggle &lt;strong&gt;&lt;strong&gt;N&lt;/strong&gt;&lt;/strong&gt;umber layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/strong&gt;oggle &lt;strong&gt;&lt;strong&gt;S&lt;/strong&gt;&lt;/strong&gt;ymbols layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/strong&gt;oggle &lt;strong&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/strong&gt;aps lock escape swap&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section id=&quot;CAPSWORD&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#CAPSWORD&quot; class=&quot;heading-ref&quot;&gt;CAPSWORD&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CAPSWORD is a “smart caps lock”. It works like a regular caps lock, except it automatically turns off after certain keys are typed (most commonly space).&lt;/p&gt;
&lt;p&gt;It will not turn off on these keys: &lt;code&gt;a-z&lt;/code&gt; &lt;code&gt;å&lt;/code&gt; &lt;code&gt;ä&lt;/code&gt; &lt;code&gt;ö&lt;/code&gt; &lt;code&gt;_&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;Backspace&lt;/code&gt; and &lt;code&gt;Repeat&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;NUMWORD&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#NUMWORD&quot; class=&quot;heading-ref&quot;&gt;NUMWORD&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NUMWORD is a “smart layer”. It’s similar to &lt;a href=&quot;#CAPSWORD&quot;&gt;CAPSWORD&lt;/a&gt;, except it’s for the &lt;a href=&quot;#Numbers&quot;&gt;numbers layer&lt;/a&gt; instead of caps lock.&lt;/p&gt;
&lt;p&gt;It will not turn off on these keys: &lt;code&gt;0-9&lt;/code&gt; &lt;code&gt;%&lt;/code&gt; &lt;code&gt;+&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;_&lt;/code&gt; &lt;code&gt;.&lt;/code&gt; &lt;code&gt;,&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;=&lt;/code&gt; &lt;code&gt;x&lt;/code&gt; &lt;code&gt;Backspace&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt; &lt;code&gt;Reverse Repeat&lt;/code&gt; and &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Repeat-key&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Repeat-key&quot; class=&quot;heading-ref&quot;&gt;Repeat key&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The repeat key simply repeats the previous key. So to type &lt;code&gt;fall&lt;/code&gt; I can type &lt;code&gt;f&lt;/code&gt; &lt;code&gt;a&lt;/code&gt; &lt;code&gt;l&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt;, using four different fingers instead of pressing &lt;code&gt;l&lt;/code&gt; twice. It can also repeat things like &lt;code&gt;Ctrl-c&lt;/code&gt; or &lt;code&gt;Delete&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There’s also a reverse repeat key that “reverses” the last pressed key. The idea is that if you pressed &lt;code&gt;PageUp&lt;/code&gt; a bunch, but went too far, you could press &lt;code&gt;Reverse Repeat&lt;/code&gt; to output &lt;code&gt;PageDown&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;/blog/2021/09/05/t-34-0/&quot; title=&quot;The T-34/0 keyboard layout&quot;&gt;T-34/0&lt;/a&gt; for the introduction of the &lt;a href=&quot;/blog/2021/09/05/t-34-0/#the-repeat-key&quot; title=&quot;Repeat key&quot;&gt;repeat key&lt;/a&gt; and &lt;a href=&quot;/blog/2021/09/05/t-34-0/#reverse-repeat&quot; title=&quot;Reverse repeat key&quot;&gt;reverse repeat key&lt;/a&gt; for some more information about them.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;More-info&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#More-info&quot; class=&quot;heading-ref&quot;&gt;More info&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While I try to keep this post updated, &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/ferris/keymaps/treeman&quot; title=&quot;QMK source code&quot;&gt;reading the code&lt;/a&gt; will always give you a more up to date reference. If you’re interested in &lt;strong&gt;why&lt;/strong&gt; the layout looks like it does, I try to write the motivations in the &lt;a href=&quot;/series/t-34/&quot; title=&quot;The T-34 keyboard layout&quot;&gt;T-34 series&lt;/a&gt;.&lt;/p&gt;

&lt;/section&gt;
&lt;section class=&quot;changelog&quot;&gt;&lt;hr /&gt;&lt;ul class=&quot;items&quot;&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2024-11-27T00:00:00Z&quot; title=&quot;November 27, 2024&quot;&gt;November 27, 2024&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Update the graphics to use embedded svgs generated from the source code.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2023-11-03T00:00:00Z&quot; title=&quot;November  3, 2023&quot;&gt;November  3, 2023&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Add &lt;code&gt;@u&lt;/code&gt; to number layer for easier execution of Neovim macros (e.g. &lt;code&gt;17@u&lt;/code&gt;)&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2022-10-24T00:00:00Z&quot; title=&quot;October 24, 2022&quot;&gt;October 24, 2022&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;ol&gt;
&lt;li&gt;
Add the Windows layer to enable windows switching using &lt;code&gt;Alt-Tab&lt;/code&gt; and &lt;code&gt;Ctrl-Alt-Tab&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Move &lt;code&gt;PgUp&lt;/code&gt; to the home row pinky on the navigation layer.
&lt;/li&gt;
&lt;li&gt;
Use the &lt;code&gt;QWERTY&lt;/code&gt; layout for the shortcut layer on the left side.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2022-08-28T00:00:00Z&quot; title=&quot;August 28, 2022&quot;&gt;August 28, 2022&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;Another &lt;a href=&quot;/blog/2022/08/28/the_t-342_keyboard_layout&quot;&gt;large update&lt;/a&gt; that swaps &lt;code&gt;A&lt;/code&gt; &lt;code&gt;O&lt;/code&gt; and &lt;code&gt;I&lt;/code&gt; &lt;code&gt;U&lt;/code&gt;, reduces inner thumb key usage, makes layers accessible via home-row combos, reworks the symbols, and more.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2021-12-15T00:00:00Z&quot; title=&quot;December 15, 2021&quot;&gt;December 15, 2021&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;&lt;a href=&quot;/blog/2021/12/15/t-34-1&quot;&gt;This update&lt;/a&gt; moves the repeat key, adds a shortcut layer, and moves modifiers to combos.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li class=&quot;item&quot;&gt;
      &lt;time datetime=&quot;2021-09-05T00:00:00Z&quot; title=&quot;September  5, 2021&quot;&gt;September  5, 2021&lt;/time&gt;
      &lt;div class=&quot;description&quot;&gt;
          
&lt;p&gt;A major update &lt;a href=&quot;/blog/2021/09/05/t-34-0&quot;&gt;documented in this post&lt;/a&gt; that introduces the repeat key, moves around keys on the base layer, reworks the symbols layer, and more.&lt;/p&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
</content></entry><entry><title>Rewriting my blog in Rust for fun and profit</title><id>http://jonashietala.se/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit/index.html</id><updated>2026-04-27T10:06:38+00:00</updated><link href="https://www.jonashietala.se/blog/2022/08/29/rewriting_my_blog_in_rust_for_fun_and_profit" rel="alternate"/><published>2022-08-29T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Background&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Background&quot; class=&quot;heading-ref&quot;&gt;Background&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve used &lt;a href=&quot;https://jaspervdj.be/hakyll/&quot; title=&quot;Hakyll static site generator&quot;&gt;Hakyll&lt;/a&gt; as my static site generator for around 9 years now. Before that I think I used &lt;a href=&quot;https://jekyllrb.com/&quot; title=&quot;Simple, blog-aware, static sites&quot;&gt;Jekyll&lt;/a&gt; and also more dynamic pages with &lt;a href=&quot;https://mojolicious.org/&quot; title=&quot;Perl real-time web framework&quot;&gt;Mojolicious&lt;/a&gt; in Perl and &lt;a href=&quot;https://kohanaframework.org/&quot; title=&quot;The Switft PHP Framework&quot;&gt;Kohana&lt;/a&gt; in PHP, but I can’t be completely sure as the git history doesn’t go back that far.&lt;/p&gt;
&lt;p&gt;But all good things come to an end and I’ve now migrated to my own custom site generator written in Rust.&lt;/p&gt;
&lt;section id=&quot;Problems-with-my-previous-setup&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Problems-with-my-previous-setup&quot; class=&quot;heading-ref&quot;&gt;Problems with my previous setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are the main annoyances I wanted to solve with this rewrite:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It was starting to get slow.&lt;/p&gt;
&lt;p&gt;On my crappy laptop a full site rebuild took 75 seconds. (Not compile, just to generate the site.) I only have 240 posts so I don’t think it should be that slow. While there is a good caching system and a watch command that only updates the changed post during editing, it was still annoyingly slow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Several external dependencies.&lt;/p&gt;
&lt;p&gt;While the site generator itself is written in Haskell, there were other dependencies apart from a number of Haskell libs. My blog helper script was written in Perl, I used &lt;a href=&quot;https://github.com/sass/sassc&quot; title=&quot;libsass command line driver&quot;&gt;sassc&lt;/a&gt; to convert sass, &lt;a href=&quot;https://pygments.org/ &amp;quot;Python syntax highlighter&amp;quot;&quot;&gt;pygments&lt;/a&gt; in Python for syntax highlighting, and &lt;a href=&quot;https://github.com/s3tools/s3cmd &amp;quot;S3cmd tool for Amazon Simple Storage Service (S3)&amp;quot;&quot;&gt;s3cmd&lt;/a&gt; for uploading the generated site to S3.&lt;/p&gt;
&lt;p&gt;It’s annoying to install all these and to keep them up-to-date, it would be great to just have a single thing to worry about.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup problems.&lt;/p&gt;
&lt;p&gt;Related to the previous point, sometimes things just break and I have to spend time to debug and fix them. This is especially frustrating when I have some good idea of something to write about, just to find out that I have some issue with my site generator.&lt;/p&gt;
&lt;p&gt;You might think, what could possibly go wrong?&lt;/p&gt;
&lt;p&gt;Well, sometimes I update some packages that might break things in weird ways. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;After GHC is updated it &lt;a href=&quot;/blog/2020/05/09/ghc_cannot_find_cabal_packages/&quot; title=&quot;ghc 8.8.3 cannot find cabal 3.0.0.0 packages&quot;&gt;can no longer find cabal packages&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When I run the Haskell binary on I get this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;[ERROR] Prelude.read: no parse
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Only on my desktop, it works fine on my laptop.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Or this Perl error:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Magic.c: loadable library and perl binaries are mismatched (got handshake key 0xcd00080, needed 0xeb00080)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Only on my laptop, it works fine on my desktop.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When Hakyll changed Pandoc arguments between versions, &lt;a href=&quot;https://github.com/jaspervdj/hakyll/issues/662&quot; title=&quot;GitHub: Syntax highlighting creating anchor tags? #662&quot;&gt;breaking code rendering in my Atom feed&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know that these are all solvable, but I just want something that just works™.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mental overhead with Haskell.&lt;/p&gt;
&lt;p&gt;I kind of like Haskell—especially the purely functional parts of it, and I am a fan of the declarative approach Hakyll takes to site configuration. Take the generation of static (i.e. standalone pages) for instance:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;match &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;static/*.markdown&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    route   staticRoute
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    compile &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; pandocCompiler streams
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; loadAndApplyTemplate &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;templates/static.html&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; siteCtx
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; loadAndApplyTemplate &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;templates/site.html&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; siteCtx
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; deIndexUrls
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Even if you don’t understand the 
&lt;code class=&quot;highlight haskell&quot;&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt;&lt;/code&gt; and 
&lt;code class=&quot;highlight haskell&quot;&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;/code&gt;, I still think it’s clear that we’re finding files from the &lt;code&gt;static/&lt;/code&gt; folder, sending them to &lt;code&gt;pandocCompiler&lt;/code&gt; (to convert from markdown), to some templates and then de-indexing urls (to avoid links ending with &lt;code&gt;index.html&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Simple and clear!&lt;/p&gt;
&lt;p&gt;But I haven’t used Haskell in years, and the overhead for me to add slightly more complex things to the site is quite large.&lt;/p&gt;
&lt;p&gt;For example, I wanted to add next/prev links to posts, but then I had to spend some time relearning Haskell and Hakyll. And even then the solution I came up with was super slow because it was a linear search to find the next/previous posts, but I couldn’t figure out how to do this properly with the way Hakyll is setup.&lt;/p&gt;
&lt;p&gt;I’m sure you can do it in an efficient manner, but for me it was too much effort for such a small feature for me to bother.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-Rust&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-Rust&quot; class=&quot;heading-ref&quot;&gt;Why Rust?&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
I enjoy using Rust, and it’s important for a hobby project like this.
&lt;/li&gt;
&lt;li&gt;
Rust is quite performant and transforming text is a task it should be good at.
&lt;/li&gt;
&lt;li&gt;
Cargo is fire and forget. As long as you have Rust installed, it should be enough to just do &lt;code&gt;cargo build&lt;/code&gt; and it should just work™.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-reinvent-the-wheel-again&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Why-reinvent-the-wheel-again&quot; class=&quot;heading-ref&quot;&gt;Why reinvent the wheel again?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I wanted to write my own static site generator as a fun and interesting project. It shouldn’t be &lt;strong&gt;that&lt;/strong&gt; hard and it would give me complete control over the site, which should give me a bit more flexibility than if I used an existing site generator.&lt;/p&gt;
&lt;p&gt;(Yes I know that projects like &lt;a href=&quot;https://cobalt-org.github.io/docs/&quot; title=&quot;cobalt.rs site generator&quot;&gt;cobalt&lt;/a&gt; allows you to make any kind of transformation, using whatever language you want, to your pages.)&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Implementation-details&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Implementation-details&quot; class=&quot;heading-ref&quot;&gt;Implementation details&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m not going to describe everything I did here, take a look at the &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot; title=&quot;Source code to this site&quot;&gt;source code&lt;/a&gt; if you’re interested.&lt;/p&gt;
&lt;section id=&quot;Delegate-the-hard-things&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Delegate-the-hard-things&quot; class=&quot;heading-ref&quot;&gt;Delegate the hard things&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At first I was worried that it would be hard to replicate all the features I enjoyed with Hakyll, like the templating engine, the syntax highlighting for numerous languages or the &lt;code&gt;watch&lt;/code&gt; command that automatically regenerates any pages you edit and acts as a file server so I can view the post in the browser during the writing process.&lt;/p&gt;
&lt;p&gt;Turns out that it’s easy if you let existing crates handle the hard parts. Here are some of the libraries I used to good effect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://tera.netlify.app/&quot; title=&quot;A powerful, easy to use template engine for Rust&quot;&gt;tera&lt;/a&gt; for a templating engine.&lt;/p&gt;
&lt;p&gt;It’s more powerful than what Hakyll provides, as it can do things like loop:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;post-footer&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;nav&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;tag-links&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      Posted in {% for tag in tags %}{% if loop.index0 &amp;gt; 0 %}, {% endif %}&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;{{ tag.href }}&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;{{ tag.name }}&lt;span class=&quot;meta tag inline a html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline a html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;{% endfor %}.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;nav&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/pulldown-cmark&quot; title=&quot;A pull parser for CommonMark&quot;&gt;pulldown-cmark&lt;/a&gt; for parsing Markdown.&lt;/p&gt;
&lt;p&gt;It’s really for &lt;a href=&quot;https://commonmark.org/&quot; title=&quot;A strongly defined, highly compatible specification of Markdown&quot;&gt;CommonMark&lt;/a&gt; which is a standard, unambiguous syntax specification for Markdown.&lt;/p&gt;
&lt;p&gt;While fast, it doesn’t support as many things as &lt;a href=&quot;https://pandoc.org/MANUAL.html&quot; title=&quot;Pandoc&quot;&gt;Pandoc&lt;/a&gt; does, so I had to extend it with some more features. More on that later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/syntect&quot; title=&quot;library for high quality syntax highlighting and code intelligence using Sublime Text&apos;s grammars&quot;&gt;syntect&lt;/a&gt; for syntax highlighting, supporting Sublime Text’s grammars.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/yaml-front-matter&quot; title=&quot;YAML Front Matter (YFM) parser for Markdown files &quot;&gt;yaml-front-matter&lt;/a&gt; to parse metadata from posts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/grass&quot; title=&quot;A near-feature-complete Sass compiler written purely in Rust&quot;&gt;grass&lt;/a&gt; as a Sass compiler purely in Rust.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/axum&quot; title=&quot;Web framework that focuses on ergonomics and modularity&quot;&gt;axum&lt;/a&gt; to create &lt;a href=&quot;https://github.com/tokio-rs/axum/tree/main/examples/static-file-server&quot; title=&quot;A strongly defined, highly compatible specification of Markdown&quot;&gt;a static file server&lt;/a&gt; used to host the site locally.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/hotwatch&quot; title=&quot;A Rust library for conveniently watching and handling file changes&quot;&gt;hotwatch&lt;/a&gt; to watch for file changes, so we can update pages whenever a file is updated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/scraper&quot; title=&quot;HTML parsing and querying with CSS selectors&quot;&gt;scraper&lt;/a&gt; to parse the generated html. Used in some of my tests and for some specific transformations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/rust-s3&quot; title=&quot;Rust library for working with Amazon S3 and compatible object storage APIs&quot;&gt;rust-s3&lt;/a&gt; to upload the generated site to S3 storage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even with these libraries the Rust source files themselves contained over 6000 lines. In some cases Rust can be verbose, and my code is really not beautiful, but writing this project was still more work than expected. (Isn’t that always the case?)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Markdown-transformations&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Markdown-transformations&quot; class=&quot;heading-ref&quot;&gt;Markdown transformations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While it would be easy if my posts were just standard markdown, over the years I’ve included various features and extensions that my markdown parsers of choice &lt;a href=&quot;https://crates.io/crates/pulldown-cmark&quot; title=&quot;A pull parser for CommonMark&quot;&gt;pulldown-cmark&lt;/a&gt; don’t support. So I had to code them myself.&lt;/p&gt;
&lt;section id=&quot;Preprocessing&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#Preprocessing&quot; class=&quot;heading-ref&quot;&gt;Preprocessing&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I have a preprocessing step that I use to create figures with multiple images. It’s a generalized processing step that takes the form:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;::: &lt;type&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;content&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:::
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I use this for different kinds of image collections, such as &lt;code&gt;Flex&lt;/code&gt;, &lt;code&gt;Figure&lt;/code&gt; and &lt;code&gt;Gallery&lt;/code&gt;. For example this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;::: Flex
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;/images/img1.png
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;/images/img2.png
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;/images/img3.png
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Figcaption goes here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:::
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Would be transformed to:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figure&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;flex-33&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/img1.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/img2.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/img3.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figcaption&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Figcaption goes here&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figcaption&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And how did I implement this magic? Using Regex of course!&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;lazy_static&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;lazy_static&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;regex&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;Captures&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Regex&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;borrow&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Cow&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support macro rust&quot;&gt;lazy_static!&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;constant other rust&quot;&gt;BLOCK&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; Regex &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Regex&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;string quoted double raw rust&quot;&gt;&lt;span class=&quot;storage type string rust&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;#&lt;/span&gt;&amp;quot;(?xsm)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ^
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        # Opening :::
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        :{3}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        \s+
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        # Parsing id type
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        (?P&amp;lt;id&amp;gt;\w+)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        \s*
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        $
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        # Content inside
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        (?P&amp;lt;content&amp;gt;.+?)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        # Ending :::
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ^:::$
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;#&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    .&lt;span class=&quot;support function rust&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;parse_fenced_blocks&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Cow&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant other rust&quot;&gt;BLOCK&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;replace_all&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;caps&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;Captures&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; String&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support function rust&quot;&gt;parse_block&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            caps.&lt;span class=&quot;support function rust&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;id&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;as_str&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            caps.&lt;span class=&quot;support function rust&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;content&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;as_str&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;parse_block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;, &lt;span class=&quot;variable parameter rust&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; String&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator rust&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(The image and figure parsing is more verbose, so let’s skip that shall we?)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Extending-pulldown_cmark&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;#Extending-pulldown_cmark&quot; class=&quot;heading-ref&quot;&gt;Extending pulldown_cmark&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I’ve also extended &lt;a href=&quot;https://crates.io/crates/pulldown-cmark&quot; title=&quot;A pull parser for CommonMark&quot;&gt;pulldown-cmark&lt;/a&gt; with transformations of my own:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Issue a warning during the build process if any markdown link is broken.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Parser&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new_with_broken_link_callback&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Options&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;all&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;support type rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; cb&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Demote headers (eg h1 -&amp;gt; h2), give them an &amp;quot;id&amp;quot; and an &amp;quot;a&amp;quot; tag.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;TransformHeaders&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Convert standalone images to figures.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;AutoFigures&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Embed raw youtube links using iframes.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;EmbedYoutube&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Syntax highlighting.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;CodeBlockSyntaxHighlight&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;InlineCodeSyntaxHighlight&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Parse `{ :attr }` attributes for blockquotes, to generate asides for instance.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;QuoteAttrs&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; parse `{ .class }` attributes for tables, to allow styling for tables.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; transformed &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;TableAttrs&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;transformed&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Demoting headers and &lt;a href=&quot;/blog/2014/09/01/embedding_youtube_videos_with_hakyll/&quot; title=&quot;Embedding youtube videos with Hakyll&quot;&gt;embedding bare YouTube links&lt;/a&gt; is something I used to do before, and were fairly straightforward do implement. (It might have been better to embed YouTube links in a pre- or post-processing step though.)&lt;/p&gt;
&lt;p&gt;Pandoc had support for adding attributes and classes to arbitrary elements, which was very useful. So for instance this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight md&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta paragraph markdown&quot;&gt;![](/images/img1.png){ height=100 }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Would be transformed into this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;/images/img1.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;100&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag other html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag other html&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I used it all over the place, so I reimplemented it… in less general and hacky manner.&lt;/p&gt;
&lt;p&gt;Another feature I used in Pandoc that wasn’t supported was evaluating markdown inside html tags. So this would no longer render correctly:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight md&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta disable-markdown&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;My [link][link_ref]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At first my plan was to do this with the generalized preprocessing step, but then I’d lose track of link references. So in this example:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight md&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta paragraph markdown&quot;&gt;::: Aside
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;My &lt;span class=&quot;meta link reference markdown&quot;&gt;&lt;span class=&quot;punctuation definition link begin markdown&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta link reference description markdown&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;meta link reference markdown&quot;&gt;&lt;span class=&quot;punctuation definition link end markdown&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta link reference markdown&quot;&gt;&lt;span class=&quot;punctuation definition constant begin markdown&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other reference link markdown&quot;&gt;link_ref&lt;/span&gt;&lt;span class=&quot;punctuation definition constant end markdown&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:::
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta link reference def markdown&quot;&gt;&lt;span class=&quot;punctuation definition constant begin markdown&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;entity name reference link markdown&quot;&gt;link_ref&lt;/span&gt;&lt;span class=&quot;punctuation definition constant end markdown&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value markdown&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;markup underline link markdown&quot;&gt;/some/path&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;link&lt;/code&gt; would not be turned into a link as we would only parse inside &lt;code&gt;:::&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight md&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta block-level markdown&quot;&gt;&lt;span class=&quot;markup quote markdown&quot;&gt;&lt;span class=&quot;punctuation definition blockquote markdown&quot;&gt;&amp;gt;&lt;/span&gt; Some text
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;{ :notice }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That would call a &lt;code&gt;notice&lt;/code&gt; parser, which in this case would create a 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; tag instead of a 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; tag, while preserving the parsed markdown.&lt;/p&gt;
&lt;p&gt;While there are existing crates that adds code highlighting using [syntect], I wrote my own that wraps it in a 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; tag and supports inline code highlighting. For example “Inside row: 
&lt;code class=&quot;highlight rust&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;&lt;/code&gt;” is produced by:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight md&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta paragraph markdown&quot;&gt;Inside row: &lt;span class=&quot;markup raw inline markdown&quot;&gt;&lt;span class=&quot;punctuation definition raw begin markdown&quot;&gt;`&lt;/span&gt;let x = 2;&lt;span class=&quot;punctuation definition raw end markdown&quot;&gt;`&lt;/span&gt;&lt;/span&gt;rust
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Performance-improvements&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Performance-improvements&quot; class=&quot;heading-ref&quot;&gt;Performance improvements&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I didn’t spend that much time into improving the performance, but two things had a significant impact:&lt;/p&gt;
&lt;p&gt;The first thing is that if you use [syntect] and have custom syntaxes, you really should &lt;a href=&quot;https://docs.rs/syntect/latest/syntect/dumps/index.html&quot;&gt;compress 
&lt;code class=&quot;highlight rust&quot;&gt;SyntaxSet&lt;/code&gt; to a binary format&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The other thing was to parallelize rendering using &lt;a href=&quot;https://docs.rs/rayon/latest/rayon/&quot; title=&quot;Data-parallelism library that makes it easy to convert sequential computations into parallel&quot;&gt;rayon&lt;/a&gt;. Rendering is the markdown parsing, applying templates and creating the output file. Rayon is great is this task is limited by CPU and it’s very easy to use (if the code is structured correctly). This is for instance a simplified view of the rendering:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;render&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Result&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; items &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support type rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Add posts, archives, and all other files that should be generated here.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; post &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.content.posts &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        items.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;post.&lt;span class=&quot;support function rust&quot;&gt;as_ref&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Render all items.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    items
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;try_for_each&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;render_item&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;item&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To parallelize this all we need to do is change 
&lt;code class=&quot;highlight rust&quot;&gt;&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; into 
&lt;code class=&quot;highlight rust&quot;&gt;&lt;span class=&quot;support function rust&quot;&gt;par_iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;rayon&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;iter&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;IntoParallelRefIterator&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; ParallelIterator&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;items
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    .&lt;span class=&quot;support function rust&quot;&gt;par_iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; This line
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    .&lt;span class=&quot;support function rust&quot;&gt;try_for_each&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;render_item&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;item&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s it!&lt;/p&gt;
&lt;p&gt;Admittedly, my performance improvements are quite minor, and the big performance gains comes from the libraries I use. For instance my old site used an external [pygments] process written in Python for syntax highlighting, while I now have a highlighter in Rust that’s &lt;strong&gt;much&lt;/strong&gt; faster, and can easily be parallelized.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Sanity-checks&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Sanity-checks&quot; class=&quot;heading-ref&quot;&gt;Sanity checks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One thing that always bothered me with the site is how easy it was to make a mistake. For example linking to a non-existent page or image, or not defining a link reference at all with &lt;code&gt;[my link][todo]&lt;/code&gt;, and forgetting to update it before publishing.&lt;/p&gt;
&lt;p&gt;So in addition to testing basic functionality like the watch command, I also parse the whole site and check that all internal links exists and are correct (so it validates &lt;code&gt;some-title&lt;/code&gt; in &lt;code&gt;/blog/my-post#some-title&lt;/code&gt; too). I also check external links, but that’s with a manual command.&lt;/p&gt;
&lt;p&gt;During generation I also take a hard stance and &lt;code&gt;panic&lt;/code&gt; early and often, just to reduce the risk that something weird slips by.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;How-did-it-go&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#How-did-it-go&quot; class=&quot;heading-ref&quot;&gt;How did it go?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the beginning of this post I listed some issues I had with my previous setup, so let’s see if I managed to improve them?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On my crappy laptop a full site rebuild (not including compilation time) now takes 4 seconds. An 18x performance improvement is not too shabby I’d say. I’m sure this could be improved further—for example I use &lt;a href=&quot;https://docs.rs/rayon/latest/rayon/&quot; title=&quot;Data-parallelism library that makes it easy to convert sequential computations into parallel&quot;&gt;rayon&lt;/a&gt; for file IO while async would be more beneficial, and I don’t have a caching system so I regenerate all files every time I build. (During watching it’s smarter though.)&lt;/p&gt;
&lt;p&gt;Please note that this is not to say that Rust this much faster than Haskell, instead see it as a comparison of two implementations. I’m sure someone could make it super fast in Haskell.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;A single dependency&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now I’ve got everything in Rust, with no external scripts or tools I need to install and keep working.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Cargo “just works”&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As long as I have rust on the system, &lt;code&gt;cargo build&lt;/code&gt; is just rock solid. I think this is low-key one of Rust’s biggest strengths—the build system &lt;strong&gt;just works&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You don’t have to manually hunt down missing dependencies, sacrifice a child to make it cross-platform or pull your hair out when the build system automagically pulls down an update that breaks everything again. You just lean back and wait for your code to compile.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;I had an easier time with Rust&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While I did find it easier to implement things like &lt;a href=&quot;/series&quot; title=&quot;Many blog posts makes a series&quot;&gt;series&lt;/a&gt; or prev/next links (which aren’t live yet as I haven’t styled them properly), I don’t think it means that Rust is simpler or easier than Haskell, it just means that I personally had an easier time to grok Rust than Haskell.&lt;/p&gt;
&lt;p&gt;The biggest reason why probably comes down to practice. While I’ve been using Rust a fair bit lately, I’ve barely touched Haskell since I started using it for this site around a decade ago.&lt;/p&gt;
&lt;p&gt;I’m sure that if I don’t use Rust for 10 years and you ask me to use it again, I’ll struggle a fair bit as well.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overall, I’m quite pleased. It was a fun—albeit a larger than I had anticipated—project that also removed some of my annoyances with this site.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>The T-34/2 keyboard layout</title><id>http://jonashietala.se/blog/2022/08/28/the_t-342_keyboard_layout/index.html</id><updated>2026-04-27T11:09:53+00:00</updated><link href="https://www.jonashietala.se/blog/2022/08/28/the_t-342_keyboard_layout" rel="alternate"/><published>2022-08-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/freq/all.png&quot; /&gt;
&lt;figcaption&gt;&lt;p&gt;The T-34/2 layout.&lt;br /&gt;
Generated with the &lt;a href=&quot;https://precondition.github.io/qmk-heatmap#how-to-collect-the-required-data&quot; title=&quot;QMK Heatmap Generator&quot;&gt;QMK Heatmap Generator&lt;/a&gt;, with all layers and combos.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It’s been 6 months since my last update on the &lt;a href=&quot;/blog/tags/t-34/&quot; title=&quot;T-34 tags&quot;&gt;T-34&lt;/a&gt; keyboard layout, and I’ve made some changes I’d like to document here.&lt;/p&gt;
&lt;p&gt;As seen in the heatmap above, the layout seems quite decent. There’s still an issue with &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; being too prominent (because I’m a Vim jk-spammer). I don’t have a good fix for it layout wise—maybe a &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; swap—but mainly I think I “just” need to get better Vim habits.&lt;/p&gt;
&lt;p&gt;There’s also a hand imbalance, but I don’t feel it’s an issue for me as I have problems with RSI on my right hand, so having the left hand do a little more work is even a positive.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/legend.png&quot; /&gt;
&lt;figcaption&gt;Legend&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Swap AO and IU (again)&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/base.png&quot; /&gt;
&lt;figcaption&gt;Base&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In my &lt;a href=&quot;/blog/2021/12/15/t-34-1/&quot; title=&quot;The T-34/1 keyboard layout&quot;&gt;last iteration&lt;/a&gt; I had &lt;code&gt;iu&lt;/code&gt; on my middle finger and &lt;code&gt;ao&lt;/code&gt; on my ring finger. That was far from optimal as the ring finger is stronger, and &lt;code&gt;ao&lt;/code&gt; is much more common for me. It was just an oversight after I swapped &lt;code&gt;Repeat&lt;/code&gt; to the home-row (from where &lt;code&gt;o&lt;/code&gt; is now) but it has now been corrected.&lt;/p&gt;
&lt;p&gt;I’ll also say that I’m still not convinced that &lt;code&gt;Repeat&lt;/code&gt; is worth it here. Avoiding double taps feels good, and repeating things like &lt;code&gt;Ctrl-c&lt;/code&gt; is fantastic, but I could see that removing &lt;code&gt;Repeat&lt;/code&gt;, moving &lt;code&gt;o&lt;/code&gt; to the home-row and making space for an extra key is the better choice.&lt;/p&gt;
&lt;h1&gt;Reduce inner thumb key usage&lt;/h1&gt;
&lt;p&gt;Another big change I’ve made is to reduce the inner thumb key usage (where I fold my thumb to reach the &lt;code&gt;SHRT&lt;/code&gt; and &lt;code&gt;SPEC&lt;/code&gt; keys). This was a big issue for my right thumb where I’m suffering from RSI (I probably read too much manga on my mobile phone).&lt;/p&gt;
&lt;h2&gt;Shortcuts&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;/blog/2021/12/15/t-34-1/&quot; title=&quot;The T-34/1 keyboard layout&quot;&gt;T-34/1&lt;/a&gt; had symbols and mods on the thumbs (only used for multiples, as I have single combos for them all) I now only have rarely used keys under the layers there:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/shrt.png&quot; /&gt;
&lt;figcaption&gt;Shortcuts under the left thumb.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The shortcuts are there to give me one-handed access to common shortcuts. There are some duplicates there as I could for instance do &lt;code&gt;Ctrl-c&lt;/code&gt; either from the shortcut layer or do a &lt;code&gt;Ctrl&lt;/code&gt; combo then &lt;code&gt;c&lt;/code&gt;, but meh.&lt;/p&gt;
&lt;h2&gt;Specials&lt;/h2&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/spec.png&quot; /&gt;
&lt;figcaption&gt;Specials under the right thumb (with ←↓↑→ symbols, not arrow keys).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ts mostly used to add accents like &lt;code&gt;é&lt;/code&gt; or &lt;code&gt;è&lt;/code&gt;, but it’s very rarely used.&lt;/p&gt;
&lt;h2&gt;Home-row combos for ctrl and layer access&lt;/h2&gt;
&lt;p&gt;I’ve also reworked the combos to give access to the symbol layers and to add a one-shot &lt;code&gt;Ctrl&lt;/code&gt; on home-row:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/hcombos.png&quot; /&gt;
&lt;figcaption&gt;Horizontal combos with nearby keys.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ctrl&lt;/code&gt; is super common, so it should have prime real estate on the home-row. I &lt;em&gt;vastly&lt;/em&gt; prefer one-shot over keys I need to hold down, and it’s super comfortable to type things like &lt;code&gt;Ctrl-n&lt;/code&gt; and &lt;code&gt;Ctrl-o&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SYM&lt;/code&gt; being a hold is fine as I only use it to output multiple symbols. It’s almost exclusively used for &lt;code&gt;{}&lt;/code&gt; and &lt;code&gt;[]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Some combos now use 3 or even 4 keys. That’s fine as they’re “big” keys that I tend to slam a bit more, so in a weird way having some more resistance feels better in some cases…&lt;/li&gt;
&lt;li&gt;Not pictured above, &lt;code&gt;;&lt;/code&gt; is triggered by &lt;code&gt;t&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt; which is a bit weird, but it works.&lt;/li&gt;
&lt;li&gt;The modifier layer exists as an escape hatch, if I ever have to type weird modifiers like &lt;code&gt;Alt&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/mods.png&quot; /&gt;
&lt;figcaption&gt;Modifiers&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Symbols&lt;/h2&gt;
&lt;p&gt;Another consequence of the change is that the two symbol layers (that &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/#Mods-symbols&quot; title=&quot;T-34 mods &amp;amp; symbols&quot;&gt;used to&lt;/a&gt; have &lt;a href=&quot;https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum#oneshot-modifiers&quot; title=&quot;Callum Oakley keymap&quot;&gt;callum style mods&lt;/a&gt; on the opposite side) are now combined into a single layer:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/sym.png&quot; /&gt;
&lt;figcaption&gt;Symbols&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A small change I did to the symbols layer is to swap &lt;code&gt;%&lt;/code&gt; and &lt;code&gt;!&lt;/code&gt;, because &lt;code&gt;%{}&lt;/code&gt;, &lt;code&gt;&amp;lt;%&lt;/code&gt; and &lt;code&gt;%&amp;gt;&lt;/code&gt; are common sequences in Elixir.&lt;/p&gt;
&lt;p&gt;I did try to have &lt;code&gt;%{}&lt;/code&gt; as a long press on &lt;code&gt;%&lt;/code&gt;, but for some reason I didn’t really use it. Rolling feels more satisfying.&lt;/p&gt;
&lt;h1&gt;Swap thumbs for number and symbol combos&lt;/h1&gt;
&lt;p&gt;Previously the easy access logic for numbers and symbols was:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Combo&lt;/th&gt;&lt;th&gt;Output&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;left thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;symbol&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;right thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;digit&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;But despite struggling for many months, I still couldn’t get used to it and I still made mistakes regularly. So now I’ve changed to this:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Combo&lt;/th&gt;&lt;th&gt;Output&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;same side thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;symbol&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;opposite thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;digit&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;For some reason, this is easier for my brain.&lt;/p&gt;
&lt;h1&gt;Even easier ÅÄÖ&lt;/h1&gt;
&lt;p&gt;I still really like the Swedish overlay (replacing &lt;code&gt;()_&lt;/code&gt; with &lt;code&gt;åäö&lt;/code&gt;), but I’ve added some extra finesse to it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When switching, if the previous key is one of &lt;code&gt;()_&lt;/code&gt; then backspace and replace it with &lt;code&gt;åäö&lt;/code&gt; (and vice versa).&lt;/p&gt;
&lt;p&gt;I find that I’m often in the wrong layer, so if I type for instance &lt;code&gt;fooå&lt;/code&gt;, I can just switch off the Swedish layer and I’ll get &lt;code&gt;foo(&lt;/code&gt;. In theory it’s good, but it doesn’t come super fluidly for me yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Combos with the opposite thumb now always output &lt;code&gt;åäö&lt;/code&gt;, which is in line with the combo swap mentioned above.&lt;/p&gt;
&lt;p&gt;This means I always have access to &lt;code&gt;()_&lt;/code&gt; and &lt;code&gt;åäö&lt;/code&gt; with the same combo, regardless of what layer I’m on.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Instant leader key&lt;/h1&gt;
&lt;p&gt;A &lt;a href=&quot;https://docs.qmk.fm/#/feature_leader_key&quot; title=&quot;QMK leader key&quot;&gt;leader key&lt;/a&gt; is a function that triggers after a sequences of keys. So for instance I press &lt;code&gt;Leader&lt;/code&gt;, then &lt;code&gt;t&lt;/code&gt; and finally &lt;code&gt;n&lt;/code&gt; to toggle the number layer. I use these sequences with the combo &lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt; as my leader key:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Sequence&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;C&lt;/strong&gt;aps lock&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;T&lt;/strong&gt;oggle &lt;strong&gt;N&lt;/strong&gt;umber layer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;T&lt;/strong&gt;oggle &lt;strong&gt;S&lt;/strong&gt;ymbols layer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;T&lt;/strong&gt;oggle &lt;strong&gt;C&lt;/strong&gt;aps lock escape swap&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;I don’t use QMK’s version, as I couldn’t get used to the timeouts, but a &lt;a href=&quot;https://github.com/andrewjrae/kyria-keymap#userspace-leader-sequences&quot; title=&quot;Userspace leader sequences&quot;&gt;userspace implementation&lt;/a&gt; that resolves instantly.&lt;/p&gt;
&lt;h1&gt;A failed experiment&lt;/h1&gt;
&lt;p&gt;As I find &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; to be the worst keys on the board (barring the folding thumb keys), I tried to have them as &lt;code&gt;h&lt;/code&gt; + &lt;code&gt;k&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; combos…&lt;/p&gt;
&lt;p&gt;But it felt so much worse. Maybe there’s a way to modify the layout to remove those two keys, but this is not the way. And it’s not something I care to explore further at the moment.&lt;/p&gt;
&lt;h1&gt;More heatmaps&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://precondition.github.io/qmk-heatmap#how-to-collect-the-required-data&quot; title=&quot;QMK Heatmap Generator&quot;&gt;QMK Heatmap Generator&lt;/a&gt; also provides heatmaps for the individual layers, which gives another way to analyze the keymap compared to an indiscriminate keylogger I’ve used before.&lt;/p&gt;
&lt;p&gt;Note that I did not take these heatmaps into account making this version of the keymap.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/freq/base.png&quot; /&gt;
&lt;figcaption&gt;Base layer (this includes virtually all combos too).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Can you feel the &lt;code&gt;j&lt;/code&gt;/&lt;code&gt;k&lt;/code&gt; abuse?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/freq/swe.png&quot; /&gt;
&lt;figcaption&gt;Swedish layer (only ÅÄÖ are changed from base).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In contrast to the base layer, which is used for programming a lot, the Swedish layer is only used for writing normally, and I think it looks decent.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/freq/sym.png&quot; /&gt;
&lt;figcaption&gt;Symbols layer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that this is only used to write multiple symbols in a row, like &lt;code&gt;%{}&lt;/code&gt; or &lt;code&gt;#[&lt;/code&gt;, as single symbols are typed with thumb combos.&lt;/p&gt;
&lt;p&gt;(And arrows like &lt;code&gt;-&amp;gt;&lt;/code&gt; and operations like &lt;code&gt;||&lt;/code&gt; are typed in other ways, so there aren’t that much usage for this layer.)&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/freq/num.png&quot; /&gt;
&lt;figcaption&gt;Numbers layer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that this is only used together with &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/#Where-are-the-digits&quot; title=&quot;Where are the digits?&quot;&gt;NUMWORD&lt;/a&gt;, and single digits are typed with thumb combos—such as &lt;code&gt;0&lt;/code&gt; that in Vim moves the cursor to the beginning of the line.&lt;/p&gt;
&lt;p&gt;A typical usage for me is to jump around in Vim with relative line numbers, which explains the high frequencies of &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/rel_vim.png&quot; /&gt;
&lt;figcaption&gt;Activate &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout/#Where-are-the-digits&quot; title=&quot;Where are the digits?&quot;&gt;NUMWORD&lt;/a&gt;, then &lt;code&gt;4j&lt;/code&gt; would move the cursor 4 lines down to &lt;code&gt;.collect&lt;/code&gt; and turn off the number layer.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/freq/nav.png&quot; /&gt;
&lt;figcaption&gt;Navigation layer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I switch windows in Vim with &lt;code&gt;Ctrl-Left&lt;/code&gt; or &lt;code&gt;Ctrl-Right&lt;/code&gt;, which is something I do all the time.&lt;/p&gt;
&lt;p&gt;Maybe there’s an argument for removing the arrows on the left, placing the tabs (switching tabs in Firefox) in a better position?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-2/freq/wnav.png&quot; /&gt;
&lt;figcaption&gt;Workspace nav layer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is basically switching between workspaces &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;9&lt;/code&gt; and the three monitors. It’s weird how I don’t use workspace &lt;code&gt;3&lt;/code&gt;, although it should be in a good position finger placement wise.&lt;/p&gt;
&lt;p&gt;There are some more layers, but I cut them out because the heatmaps were totally uninteresting to me.&lt;/p&gt;
&lt;p&gt;As usual, the &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/ferris/keymaps/treeman&quot; title=&quot;Source code for T-34&quot;&gt;firmware QMK code&lt;/a&gt; is on Codeberg.&lt;/p&gt;
</content></entry><entry><title>2021 in review</title><id>http://jonashietala.se/blog/2022/01/10/2021_in_review/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2022/01/10/2021_in_review" rel="alternate"/><published>2022-01-10T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A new year is always a good time to review the past year. Funny how this is already &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly reviews&quot;&gt;the 12&lt;sup&gt;th&lt;/sup&gt; year&lt;/a&gt; I’ve done this kind of quick review… Time sure flies.&lt;/p&gt;
&lt;h1&gt;2021 Non-Geek Achievements&lt;/h1&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;Started strength training using a strength coach from &lt;a href=&quot;https://kabukistrength.com/coaching/&quot; title=&quot;Kabuki coaching&quot;&gt;Kabuki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I got inspired by the book &lt;a href=&quot;https://www.goodreads.com/book/show/26312997-peak&quot; title=&quot;Peak: Secrets from the New Science of Expertise&quot;&gt;Peak&lt;/a&gt; that makes the case for the efficiency of having an experienced coach guide your skill development, and I decided to try out the virtual coaching. I get help with designing a program and checking my form and so far it’s been great.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote &lt;a href=&quot;/archive&quot; title=&quot;My archive&quot;&gt;8 blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Started the re-read of &lt;a href=&quot;https://joeabercrombie.com/books/&quot; title=&quot;Books by Joe Abercrombie&quot;&gt;The First Law&lt;/a&gt; series and the other books in the universe.&lt;/p&gt;
&lt;p&gt;The stand-alone books &lt;em&gt;Best Served Cold&lt;/em&gt; and &lt;em&gt;The Heroes&lt;/em&gt; are seriously great (haven’t gotten to &lt;em&gt;Read Country&lt;/em&gt; yet).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2021 Geek Achievements&lt;/h1&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;I &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;self-published a book&lt;/a&gt;!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/cover-hand.png&quot; /&gt;
&lt;figcaption&gt;It’s so real I can hold it in my hand.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Got funding for &lt;a href=&quot;https://github.com/bitpal/bitpal&quot; title=&quot;BitPal&quot;&gt;BitPal&lt;/a&gt;, an open-source project I’ve been working on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote a bunch of Rust.&lt;/p&gt;
&lt;p&gt;Bought a bunch of Rust programming books too, but the only one I’ve read yet is &lt;em&gt;Programming Rust&lt;/em&gt;, which was very good.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote a lot of Elixir.&lt;/p&gt;
&lt;p&gt;Also read a bunch of Elixir books. &lt;em&gt;Elixir in Action&lt;/em&gt; was fantastic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some C, Python, Typescript and probably something else too.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Started using a (very) &lt;a href=&quot;/blog/tags/t-34/&quot; title=&quot;T-34&quot;&gt;custom keyboard layout&lt;/a&gt; on a 34-key split keyboard.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-1/base.png&quot; /&gt;
&lt;figcaption&gt;The base layout of my keyboard layout T-34/1&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Did some web design.&lt;/p&gt;
&lt;p&gt;The book &lt;em&gt;The Non-Designer’s Design Book&lt;/em&gt; is great for design-fledglings like me.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Boardgames I remember&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Vital Lacerda&lt;/em&gt; is famous for designing thematic and very complex Eurogames. Some hate them, others maintain that they’re the best things since sliced bread, and I lean towards the latter.&lt;/p&gt;
&lt;p&gt;I bought and played three of them:&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/184267/mars&quot; title=&quot;On Mars&quot;&gt;On Mars&lt;/a&gt; is very complex with a lot of rules (it took me ~30 min to explain them, even though I skipped a bunch and came prepared). Still, it’s an absolutely amazing game and it was the highlight of the year for me.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/125153/gallerist&quot; title=&quot;The Gallerist&quot;&gt;The Gallerist&lt;/a&gt; is also on the complex side, but I still find it very approachable. Also an amazing game and it’s right up there with On Mars for me.&lt;/li&gt;
&lt;li&gt;I only played &lt;a href=&quot;https://boardgamegeek.com/boardgame/175640/vinhos-deluxe-edition&quot; title=&quot;Vinhos Deluxe Edition&quot;&gt;Vinhos&lt;/a&gt; once. While it’s undoubtedly a very good game, it has taken a step back compared to the two other Lacerdas. I’d like to play it more.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://boardgamegeek.com/boardgame/175914/food-chain-magnate&quot; title=&quot;Food Chain Magnate&quot;&gt;Food Chain Magnate&lt;/a&gt; is easily one of my favorite games of all time, and I got to play a game with the new milestones from the &lt;a href=&quot;https://boardgamegeek.com/boardgameexpansion/261526/food-chain-magnate-ketchup-mechanism-other-ideas&quot; title=&quot;Food Chain Magnate: The Ketchup Mechanism &amp;amp; Other Ideas&quot;&gt;Ketchup expansion&lt;/a&gt;. And what can I say? It was great, and if you want more variation to the game the expansion is fantastic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My kid is now 4 years old and at long last he’s old enough to play some decent board games. Both me and him liked &lt;a href=&quot;https://boardgamegeek.com/boardgame/17329/animal-upon-animal&quot;&gt;Animal Upon Animal&lt;/a&gt; and &lt;a href=&quot;https://boardgamegeek.com/boardgame/91514/rhino-hero&quot;&gt;Rhino Hero&lt;/a&gt;, which are fun enough to play with adults as well!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;New mangas/manwhas I remember&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Tired of unoriginal OP MCs? Want a smart MC and clever story?&lt;/p&gt;
&lt;p&gt;Then &lt;em&gt;SSS-Class Suicide Hunter&lt;/em&gt; or &lt;em&gt;Omniscent Reader’s Viewpoint&lt;/em&gt; might be for you! (I hear the light novels are amazing too.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maybe you still want awesome action, but avoid the common tropes?&lt;/p&gt;
&lt;p&gt;Then check out &lt;em&gt;Legend of the Northern Blade&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Perhaps your thing is regression stories?&lt;/p&gt;
&lt;p&gt;I loved &lt;em&gt;The Beginning After the End&lt;/em&gt; and &lt;em&gt;Volcanic Age&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Or a satisfying combination of fighting and humor?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Murim Login&lt;/em&gt; is half-part hilarity and half-part awesomeness.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2021 Failures&lt;/h1&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;My book project wasn’t completely finished.&lt;/p&gt;
&lt;p&gt;I still need to finish the e-book and make it available for sale.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Did not advance &lt;a href=&quot;https://github.com/bitpal/bitpal&quot; title=&quot;BitPal&quot;&gt;BitPal&lt;/a&gt; into a useable state.&lt;/p&gt;
&lt;p&gt;This is my open source cryptocurrency payment processor I’ve been working on. Unfortunately, it’s still not in a state where I’d be comfortable for others to use. Apart from the missing documentation, the web interface is still work-in-progress and there are some breaking changes to the API I’d like to make.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2022&lt;/h1&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;Be with my kids.&lt;/p&gt;
&lt;p&gt;They’re in a lovely age right now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finish my book project for real.&lt;/p&gt;
&lt;p&gt;This includes making the e-book, some blog posts about the process, integrate with BitPal to sell digital copies and everything else to completely wrap-up the project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exercise &amp;amp; health focus.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I will eat healthier.&lt;/li&gt;
&lt;li&gt;I will continue working with my strength coach.&lt;/li&gt;
&lt;li&gt;I will exercise up to 5 days a week (weight lifting + grappling).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(I’m working on converting these to &lt;a href=&quot;https://www.indeed.com/career-advice/career-development/smart-goals&quot; title=&quot;SMART Goals&quot;&gt;SMART goals&lt;/a&gt;. We’ll see how that goes, maybe I’ll make another post about them, but maybe not.)&lt;/p&gt;
</content></entry><entry><title>The T-34/1 keyboard layout</title><id>http://jonashietala.se/blog/2021/12/15/t-34-1/index.html</id><updated>2026-04-27T11:10:18+00:00</updated><link href="https://www.jonashietala.se/blog/2021/12/15/t-34-1" rel="alternate"/><published>2021-12-15T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is the revision of the &lt;a href=&quot;/blog/tags/t-34/&quot;&gt;T-34&lt;/a&gt; keyboard layout that I use as my primary driver. I’ve used this particular version without any major changes for almost 3 months, so I’d say it’s a good improvement over the last revision.&lt;/p&gt;
&lt;p&gt;There are two large changes from &lt;a href=&quot;/blog/2021/09/05/t-34-0/&quot;&gt;T-34/0&lt;/a&gt;: swapping &lt;code&gt;o&lt;/code&gt; and &lt;code&gt;Repeat&lt;/code&gt; and preferring modifiers on combos over &lt;a href=&quot;https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum#oneshot-modifiers&quot; title=&quot;Callum Oakley keymap&quot;&gt;callum-style mods&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Swap O and Repeat&lt;/h1&gt;
&lt;p&gt;I do like the &lt;code&gt;Repeat&lt;/code&gt; key, and although I tried to find a good place for it, having it on the same finger as &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt; and &lt;code&gt;.&lt;/code&gt; is not ideal. Even though &lt;code&gt;aa&lt;/code&gt; and &lt;code&gt;((&lt;/code&gt; aren’t common, having &lt;code&gt;a&lt;/code&gt; follow a double consonant—such as in the Swedish word &lt;code&gt;falla&lt;/code&gt; (to fall)—is.&lt;/p&gt;
&lt;p&gt;So I tried to swap &lt;code&gt;o&lt;/code&gt; and &lt;code&gt;Repeat&lt;/code&gt;, placing &lt;code&gt;o&lt;/code&gt; on the top row and &lt;code&gt;Repeat&lt;/code&gt; on the home row, but on the little finger:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-1/base.png&quot; /&gt;
&lt;figcaption&gt;Base layer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Because I don’t press &lt;code&gt;.&lt;/code&gt; with the pinky, &lt;code&gt;Repeat&lt;/code&gt; is only shared with a single key: &lt;code&gt;_&lt;/code&gt;, which is great!&lt;/p&gt;
&lt;p&gt;Of course, there are some trade-offs with it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;When I code and type names like &lt;code&gt;__MODULE__&lt;/code&gt; or &lt;code&gt;call_fun&lt;/code&gt;, I sometimes have SFB with the pinky (which is very uncomfortable). Adding a long-press to &lt;code&gt;_&lt;/code&gt; for &lt;code&gt;__&lt;/code&gt; helps a little.&lt;/p&gt;
&lt;p&gt;You might wonder then why I don’t swap &lt;code&gt;,&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt;? Two reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;,&lt;/code&gt; is much more common than &lt;code&gt;_&lt;/code&gt;, and I would instead get SFB from things like &lt;code&gt;fall,&lt;/code&gt;, which is not a good trade-off.&lt;/li&gt;
&lt;li&gt;On my Swedish layer, &lt;code&gt;_&lt;/code&gt; is changed to &lt;code&gt;ö&lt;/code&gt;, but I still want &lt;code&gt;,&lt;/code&gt; when I type Swedish so &lt;code&gt;ö&lt;/code&gt; would get a very weird position.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Repeat&lt;/code&gt; is still &lt;a href=&quot;/blog/2021/09/05/t-34-0#numbers&quot;&gt;on the top row&lt;/a&gt; on the numbers layer, which breaks symmetry and hurts learning.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My right pinky is by far my weakest finger, and sometimes I want to press &lt;code&gt;Repeat&lt;/code&gt; a lot of time in succession (to repeat &lt;code&gt;Ctrl-n&lt;/code&gt; for instance).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Moving &lt;code&gt;o&lt;/code&gt; away from the home row is unfortunate as it is one of the &lt;a href=&quot;/blog/2021/09/05/t-34-0#the-repeat-key&quot;&gt;most common keys&lt;/a&gt;. It’s not the end of the world though as &lt;code&gt;Repeat&lt;/code&gt; is also &lt;a href=&quot;/blog/2021/09/05/t-34-0#the-repeat-key&quot;&gt;quite common&lt;/a&gt;, the &lt;code&gt;ao&lt;/code&gt; bigram isn’t that problematic, and rolling &lt;code&gt;io&lt;/code&gt; is still okay. It also makes the &lt;code&gt;ou&lt;/code&gt; roll great.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But all-in-all, after 3 months of feeling it out, I think this change is a large improvement.&lt;/p&gt;
&lt;h1&gt;Modifiers&lt;/h1&gt;
&lt;p&gt;Another thing I’ve been slightly annoyed with is mods. I’ve been using &lt;a href=&quot;https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum#oneshot-modifiers&quot; title=&quot;Callum Oakley keymap&quot;&gt;callum-style mods&lt;/a&gt;, where you essentially press the inner thumb key and then a mod on the home-row. There are no timings here, so you can tap them as quickly as you can.&lt;/p&gt;
&lt;p&gt;This does feel great timing wise, but for me the tucking of the thumb to reach the inner thumb key feels awkward and uncomfortable. Especially for my right thumb, where I’ve been having pain issues for the last year or so.&lt;/p&gt;
&lt;p&gt;(And when I say &lt;em&gt;inner&lt;/em&gt; thumb keys, I mean &lt;code&gt;SHRT RSYM&lt;/code&gt; and &lt;code&gt;MOD LSYM&lt;/code&gt;, not &lt;code&gt;Space&lt;/code&gt; and &lt;code&gt;E&lt;/code&gt; which are super comfortable.)&lt;/p&gt;
&lt;h2&gt;Modifiers on combos&lt;/h2&gt;
&lt;p&gt;So I started thinking of alternatives, and as I have a hard-on for combos and I use them everywhere, why not place mods on combos?&lt;/p&gt;
&lt;p&gt;I did use a keylog when I started creating the layout, but it didn’t tell me much modifier wise; &lt;code&gt;Shift&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt; and &lt;code&gt;Gui&lt;/code&gt; all had about the same amount of usage, and for some reason &lt;code&gt;Alt&lt;/code&gt; was never registered. Instead, I used my &lt;a href=&quot;https://github.com/treeman/dotfiles&quot;&gt;dotfiles&lt;/a&gt; and used &lt;del&gt;the force&lt;/del&gt; felt out a modifier ranking:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Ctrl&lt;/code&gt;. Even though I use Vim, where you prefer &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; over &lt;code&gt;Ctrl-n&lt;/code&gt; and &lt;code&gt;Ctrl-p&lt;/code&gt;, I do have a lot of &lt;code&gt;Ctrl&lt;/code&gt; keybindings I use on a daily basis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Gui&lt;/code&gt;. I use &lt;code&gt;Gui&lt;/code&gt; as my window manager prefix (to change windows, workspaces, open a terminal etc). A dedicated mod key isn’t as important as I have &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout#Navigation&quot;&gt;dedicated navigation layers&lt;/a&gt;, but still.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt;. Although I’ve tried to reduce other key combinations, I still use it occasionally (copy/paste from terminal for instance). This really isn’t required, but it’s a small quality of life.&lt;/p&gt;
&lt;p&gt;(Confession time: as I’m writing this post I realize that my &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; implementation is completely broken and has never even worked. Guess it wasn’t so important after all.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;While &lt;code&gt;Shift&lt;/code&gt; was (slightly) the most used modifier in my keylog, I’ve moved on to &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot;&gt;auto shift&lt;/a&gt; so it’s not at all important. There’s still some usage for it, for instance to &lt;code&gt;Shift&lt;/code&gt; + mouse select in file browsers, so it’s good to have especially on the left side.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Everything else. I don’t use &lt;code&gt;Alt&lt;/code&gt; in any Vim command, but it still needs to be available (to open the browser menu for instance). Ideally I’d like to freely combine mods in weird ways if some program requires it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I already have a lot of combos, so it was a bit of a struggle to find good positions, but here’s what I ended up with:&lt;/p&gt;
&lt;figure&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/lgui.png&quot; /&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/rgui.png&quot; /&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/lctrl.png&quot; /&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/rctrl.png&quot; /&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/lshft.png&quot; /&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/rshft.png&quot; /&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/lctrl-shift.png&quot; /&gt;
&lt;img height=&quot;180&quot; src=&quot;/images/t-34-1/rctrl-shift.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;Ctrl&lt;/code&gt; combo is &lt;em&gt;slightly&lt;/em&gt; awkward with the home/bottom split, but it’s not too bad. Maybe it would be better as a home-row combo, but I’m very happy with the combos I have there…&lt;/p&gt;
&lt;h2&gt;Other mod combinations&lt;/h2&gt;
&lt;p&gt;I still have the same modifier setup on the right-hand side, allowing me to easily make whatever modifier combination I need:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-1/rmod.png&quot; /&gt;
&lt;figcaption&gt;Mods &amp;amp; symbols&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Common shortcuts&lt;/h2&gt;
&lt;p&gt;With mods out of the way, we can now have a shortcut layer on the left side:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-1/lmod.png&quot; /&gt;
&lt;figcaption&gt;Shortcuts &amp;amp; symbols&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The idea is to have the common shortcuts reachable with the left hand so I can use mouse-required software conveniently. I only really need the keys that are on the left-side in qwerty and on the right side in my layout (&lt;code&gt;w&lt;/code&gt;, &lt;code&gt;e&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt;), but I added others as well to make them slightly easier.&lt;/p&gt;
&lt;p&gt;Am I thrilled about the layout of the shortcuts? No, but it has worked well enough for it’s purpose.&lt;/p&gt;
&lt;p&gt;As for &lt;code&gt;Repeat&lt;/code&gt;, it takes the same place on the pinky as on the base layer, and &lt;code&gt;^&lt;/code&gt; takes the top row as the old combo location has been taken by a modifier.&lt;/p&gt;
&lt;h1&gt;Future experiments&lt;/h1&gt;
&lt;p&gt;While I haven’t made any changes to the layout for a while, I’ve been keeping notes of ideas I get of or things that annoys me. And here are the big things I’d like to try when I have the time and energy to play with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Swap num/sym thumb combos.&lt;/p&gt;
&lt;p&gt;I currently have &lt;code&gt;left thumb&lt;/code&gt; + &lt;code&gt;key&lt;/code&gt; = &lt;code&gt;symbol&lt;/code&gt;, but I’m still tripping up sometimes as the symbol layers are triggered with the opposite thumb (hold &lt;code&gt;right thumb&lt;/code&gt; = &lt;code&gt;left side symbols&lt;/code&gt;). Therefore I’d like to try &lt;code&gt;opposite side combo&lt;/code&gt; = &lt;code&gt;symbol&lt;/code&gt; to see if my brain parses it better.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More advanced tap/hold combos.&lt;/p&gt;
&lt;p&gt;I still don’t like the inner thumb keys, so I’d like to try activating layers by holding combos instead. Just some ideas:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tap&lt;/th&gt;&lt;th&gt;Hold&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Tab&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ctrl&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Escape&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Symbols on the right&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;:&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Symbols on the left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ctrl&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Mods on the right hom-row&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note that these are all home-row combos, and this change would almost completely free up the inner thumbs for other (less used) things.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Try out &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; as combos.&lt;/p&gt;
&lt;p&gt;They’re in the worst spot (well, except the inner thumb keys) so I’d especially like to move &lt;code&gt;p&lt;/code&gt; away from it. And as I already use combos for most things, why not try &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; as well?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Instant leader keys for options.&lt;/p&gt;
&lt;p&gt;I do have separate &lt;code&gt;SPEC&lt;/code&gt; and &lt;code&gt;OPT&lt;/code&gt; layers, for things toggling a persistent numbers layer or to type &lt;code&gt;é&lt;/code&gt;, but I use them so rarely that I tend to forget their positions.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://docs.qmk.fm/#/feature_leader_key&quot;&gt;leader key&lt;/a&gt;, is a nice idea as you can use several keypresses to trigger a single function. For instance you can have:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Sequence&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Leader&lt;/code&gt; &lt;code&gt;t&lt;/code&gt; &lt;code&gt;n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;T&lt;/strong&gt;oggle &lt;strong&gt;N&lt;/strong&gt;umber layer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Leader&lt;/code&gt; &lt;code&gt;t&lt;/code&gt; &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;T&lt;/strong&gt;oggle &lt;strong&gt;C&lt;/strong&gt;aps lock&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;So to toggle numbers you only have to remember the mnemonic &lt;strong&gt;T&lt;/strong&gt;oggle &lt;strong&gt;N&lt;/strong&gt;umber to remember the sequence &lt;code&gt;Leader&lt;/code&gt; &lt;code&gt;t&lt;/code&gt; &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I have tried &lt;a href=&quot;https://docs.qmk.fm/#/feature_leader_key&quot;&gt;QMK’s leader key&lt;/a&gt; before, but with little success. It’s based on timeouts, which I for some reason found really difficult to consistently trigger (and they took a lot of memory too).&lt;/p&gt;
&lt;p&gt;But there is a &lt;a href=&quot;https://github.com/andrewjrae/kyria-keymap#userspace-leader-sequences&quot;&gt;userspace leader sequence&lt;/a&gt; that I’d like to try instead, which seems like it would solve the timing issues I had.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re interested, the &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/ferris/keymaps/treeman&quot;&gt;QMK code is on Codeberg&lt;/a&gt;. But beware, there be dragons.&lt;/p&gt;
</content></entry><entry><title>The T-34/0 keyboard layout</title><id>http://jonashietala.se/blog/2021/09/05/t-34-0/index.html</id><updated>2026-04-27T11:09:50+00:00</updated><link href="https://www.jonashietala.se/blog/2021/09/05/t-34-0" rel="alternate"/><published>2021-09-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is an update to the &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout&quot;&gt;T-34&lt;/a&gt; keyboard layout I’ve been using for a solid number of weeks. While there are more changes I’d like to try, I’m quite pleased with these changes so I figured I might as well immortalize them before I explore further. (And I do have a bunch of big changes I want to experiment with.)&lt;/p&gt;
&lt;h1&gt;The repeat key&lt;/h1&gt;
&lt;p&gt;The big change to the layout is the &lt;code&gt;Repeat&lt;/code&gt; key. The concept is simple: when you press it you repeat the last pressed key.&lt;/p&gt;
&lt;p&gt;The first usage I’m aware of is the &lt;a href=&quot;https://notgate.github.io/layout/&quot;&gt;ISRT&lt;/a&gt; layout which the repeat key to lower the same finger usage. So for example to type “call” you’d type &lt;code&gt;c&lt;/code&gt; &lt;code&gt;a&lt;/code&gt; &lt;code&gt;l&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt;, avoiding the double click on &lt;code&gt;l&lt;/code&gt;. It’s not as bad as pressing a key on the home-row and then a key on the top-row with the same finger, but it’s still annoying (especially with the pinky).&lt;/p&gt;
&lt;p&gt;So how common is the &lt;code&gt;Repeat&lt;/code&gt; key? I tried to use my code corpus to see:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/repeat-freq.svg&quot; /&gt;
&lt;figcaption&gt;The green bar represents the frequency of each character and the red bars the frequency of a repeated character. &lt;code&gt;ℛ&lt;/code&gt; is the sum of all the double characters.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;While the &lt;code&gt;Repeat&lt;/code&gt; would be useful, it does not qualify into the top 10 and so it does not out compete &lt;code&gt;Space&lt;/code&gt; or &lt;code&gt;e&lt;/code&gt; as a thumb key. (&lt;code&gt;Space&lt;/code&gt; isn’t listed in the graph so &lt;code&gt;d&lt;/code&gt; comes in at 10th place.)&lt;/p&gt;
&lt;p&gt;But it’s usefulness isn’t only in minimizing SFB, as it can easily repeat difficult keys as well. For instance I have many two- or three-key combos, and double tapping them are &lt;em&gt;not&lt;/em&gt; pleasant. I tried to solve this by holding them down to simulate double or triple taps, but with a repeat key I can just do &lt;code&gt;combo&lt;/code&gt; + &lt;code&gt;Repeat&lt;/code&gt;. Feels good!&lt;/p&gt;
&lt;p&gt;Or I can repeat modded keys. For instance to exit Elixir’s REPL IEx you need to do &lt;code&gt;Ctrl-c&lt;/code&gt; twice. I don’t like to hold down layer keys (I use one-shot layers and mods instead) so to type &lt;code&gt;Ctrl-c&lt;/code&gt; I press &lt;code&gt;Mod&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, with no pauses. To do this twice I would either need 6(!) keypresses, or using hold: &lt;code&gt;Mod&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt; (hold), &lt;code&gt;c&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;. With the repeat key it’s 4 taps, without any holds: &lt;code&gt;Mod&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, &lt;code&gt;Repeat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course you can repeat whatever you like, such as &lt;code&gt;Ctrl-Shift-Tab&lt;/code&gt; or &lt;code&gt;Shift-Gui-c&lt;/code&gt; (close window in XMonad) as well.&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;Repeat&lt;/code&gt; seems like a good idea—as long as we can find a nice place for it.&lt;/p&gt;
&lt;h1&gt;Base layer&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34/legend.png&quot; /&gt;
&lt;figcaption&gt;Legend&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/base.png&quot; /&gt;
&lt;figcaption&gt;Base layer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The changes from the &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout#Base-layer&quot;&gt;previous version&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Introducing the &lt;code&gt;Repeat&lt;/code&gt; key caused a bunch of changes to the layout:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Introduce the &lt;code&gt;Repeat&lt;/code&gt; key itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Swap &lt;code&gt;a&lt;/code&gt;/&lt;code&gt;Repeat&lt;/code&gt; and &lt;code&gt;i&lt;/code&gt;/&lt;code&gt;u&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This was a change I made even before &lt;code&gt;Repeat&lt;/code&gt; (with &lt;code&gt;.&lt;/code&gt; in it’s place). It was a suggestion from &lt;a href=&quot;https://www.reddit.com/r/KeyboardLayouts/comments/nrl8dy/the_t34_keyboard_layout/h0ltgkx/&quot;&gt;/u/phbonachi&lt;/a&gt; on Reddit, as &lt;code&gt;u&lt;/code&gt; and &lt;code&gt;i&lt;/code&gt; was much more common so they should go on the stronger middle finger.&lt;/p&gt;
&lt;p&gt;This doesn’t hold as much with &lt;code&gt;Repeat&lt;/code&gt;, but having &lt;code&gt;Repeat&lt;/code&gt; on the middle doesn’t work well as it’s awkward to press &lt;code&gt;l&lt;/code&gt; with the index and then &lt;code&gt;Repeat&lt;/code&gt; with the middle, which is the most common double bigram.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rotate &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;,&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.&lt;/code&gt; is the more common, so it goes in the more convenient spot.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move &lt;code&gt;&quot;&lt;/code&gt; and &lt;code&gt;=&lt;/code&gt; to combos, and place &lt;code&gt;/&lt;/code&gt; on base.&lt;/p&gt;
&lt;p&gt;It’s true that &lt;code&gt;&quot;&lt;/code&gt; is more common than &lt;code&gt;/&lt;/code&gt;, but now takes a relatively convenient combo on the home-row. &lt;code&gt;/&lt;/code&gt; is used a lot in paths, which caused a bunch of issues with it’s previous three-key combo placement.&lt;/p&gt;
&lt;p&gt;To make room for &lt;code&gt;Repeat&lt;/code&gt;, I had to move another symbol away from base. I chose to move &lt;code&gt;=&lt;/code&gt; to a combo, as it’s not that common (I have other solutions for &lt;code&gt;=&amp;gt;&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt; etc), and the combo is still convenient for the main use-case of &lt;code&gt; = &lt;/code&gt;. &lt;code&gt;Repeat&lt;/code&gt; also takes care of &lt;code&gt;==&lt;/code&gt; nicely.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The big decision point is where to place &lt;code&gt;Repeat&lt;/code&gt;, the other changes more or less fall out afterwards.&lt;/p&gt;
&lt;p&gt;Easiest would be to place it on a primary thumb—but it’s not even close as frequent as &lt;code&gt;Space&lt;/code&gt; or &lt;code&gt;e&lt;/code&gt; is. It might work on a secondary thumb, but that requires me to rework my mod and symbol setup, which I’m not keen to do. Moving to the secondary thumb key is also quite slow, making it unsuitable for &lt;code&gt;Repeat&lt;/code&gt; as I need to be able to press it quickly.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Repeat&lt;/code&gt; is also not quite frequent enough to warrant a position on the home-row for me, but it should be in the home-box (as in not on the edges).&lt;/p&gt;
&lt;p&gt;I think I found a decent position sharing finger with &lt;code&gt;a&lt;/code&gt; &lt;code&gt;)&lt;/code&gt; and &lt;code&gt;.&lt;/code&gt; (yes I press &lt;code&gt;.&lt;/code&gt; with the ring finger). It’s not perfect, as words such as &lt;code&gt;falla&lt;/code&gt; (to fall) cannot be typed comfortably with &lt;code&gt;Repeat&lt;/code&gt;, and I have to double tapping &lt;code&gt;l&lt;/code&gt; (or worse &lt;code&gt;Repeat&lt;/code&gt; then &lt;code&gt;a&lt;/code&gt;, which my brain wants to do). Still, neither &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt; nor &lt;code&gt;(&lt;/code&gt; are commonly followed by &lt;code&gt;Repeat&lt;/code&gt;, so in practice it works out decently well.&lt;/p&gt;
&lt;p&gt;There’s another change I made that’s unrelated to &lt;code&gt;Repeat&lt;/code&gt;, that aims to fix some issues I complained about in my &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout#Is-this-the-perfect-layout&quot;&gt;previous writeup&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Rotate &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To have &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; (up/down in Vim) in slightly better positons and to fix the troublesome &lt;code&gt;sys&lt;/code&gt; and &lt;code&gt;bj&lt;/code&gt; pairs. Unfortunately &lt;code&gt;p&lt;/code&gt; gets shafted a bit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Combos&lt;/h1&gt;
&lt;p&gt;I’ve added or altered some of &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout#Combos&quot;&gt;the combos&lt;/a&gt; as well:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/q.png&quot; /&gt;
&lt;img src=&quot;/images/t-34-0/qu.png&quot; /&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/dquo.png&quot; /&gt;
&lt;img src=&quot;/images/t-34-0/scln.png&quot; /&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/eq.png&quot; /&gt;
&lt;img src=&quot;/images/t-34-0/rev_rep.png&quot; /&gt;
&lt;/figure&gt;
&lt;ol&gt;
&lt;li&gt;I’ve added a &lt;code&gt;qu&lt;/code&gt; combo as &lt;code&gt;q&lt;/code&gt; is almost always followed by &lt;code&gt;u&lt;/code&gt;, and I moved the &lt;code&gt;q&lt;/code&gt; combo off to the side.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;&lt;/code&gt; is now a home-row combo (mirroring the &lt;code&gt;&apos;&lt;/code&gt; combo on the right-hand side) and &lt;code&gt;;&lt;/code&gt; got the three-key combo as it’s slightly harder to press than the combo for &lt;code&gt;&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;=&lt;/code&gt; is now a combo on the top row instead of on the base layer. Looks a bit weird at first glance, but it’s surprisingly convenient.&lt;/li&gt;
&lt;li&gt;I’ve been playing around with a &lt;code&gt;Reverse Repeat&lt;/code&gt; key (see below).&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Reverse repeat&lt;/h1&gt;
&lt;p&gt;One use-case I have with &lt;code&gt;Repeat&lt;/code&gt; is to type &lt;code&gt;W&lt;/code&gt; (shifted w) repeatedly. In Vim &lt;code&gt;w&lt;/code&gt; jumps to the beginning of the next “word” and &lt;code&gt;W&lt;/code&gt; to the beginning of the next “WORD” (a WORD jumps over special characters such as &lt;code&gt;-&lt;/code&gt; or &lt;code&gt;_&lt;/code&gt;). For code I find that &lt;code&gt;W&lt;/code&gt; is super useful, but using &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot;&gt;auto shift&lt;/a&gt; to repeatedly type shifted characters is &lt;em&gt;incredibly&lt;/em&gt; annoying (hold down until the shifted variant appears). Therefore I use &lt;code&gt;W&lt;/code&gt; (auto shift) &lt;code&gt;Repeat&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt;…&lt;/p&gt;
&lt;p&gt;But sometimes I jump too far, so I’ll go back with &lt;code&gt;B&lt;/code&gt; (again using auto shift). Or I’ll do &lt;code&gt;Ctrl-d&lt;/code&gt; (half screen down) and I correct with &lt;code&gt;Ctrl-u&lt;/code&gt;, or &lt;code&gt;PgDn&lt;/code&gt; and correct with &lt;code&gt;PgUp&lt;/code&gt;, or &lt;code&gt;Ctrl-o&lt;/code&gt; and &lt;code&gt;Ctrl-i&lt;/code&gt;, or … You get the point.&lt;/p&gt;
&lt;p&gt;This is how the idea of the &lt;code&gt;Reverse Repeat&lt;/code&gt; key was born. It’s a key that moves in the opposite direction of &lt;code&gt;Repeat&lt;/code&gt; (mostly in Vim context). So instead of &lt;code&gt;PgDn&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt; (oops, too far) &lt;code&gt;PgUp&lt;/code&gt; I’ll do &lt;code&gt;PgDn&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt; &lt;code&gt;Repeat&lt;/code&gt; &lt;code&gt;Reverse Repeat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s a list of some of these “repeat pairs” that I’ve found useful:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;A&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;B&lt;/th&gt;&lt;th&gt; &lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;PgUp&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;PgDn&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-f&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-u&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-d&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-o&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-i&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Easily my most used pair&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-n&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Ctrl-p&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;B&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;{&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Gui-k&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;Gui-j&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This may sound fine and dandy, but if I’m completely honest, it’s absolutely nothing groundbreaking. I might use it once per day or something—and when I do it feels great—but it would be easy to live without.&lt;/p&gt;
&lt;h1&gt;Symbols&lt;/h1&gt;
&lt;p&gt;The changes to &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout#Mods-symbols&quot;&gt;the symbols&lt;/a&gt; are to move &lt;code&gt;@&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;,&lt;/code&gt;, &lt;code&gt;&quot;&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;=&lt;/code&gt; and &lt;code&gt;Repeat&lt;/code&gt; mirroring the changes to the base layer.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/lmod.png&quot; /&gt;
&lt;figcaption&gt;Left mods &amp;amp; symbols&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/rmod.png&quot; /&gt;
&lt;figcaption&gt;Right mods &amp;amp; symbols&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Numbers&lt;/h1&gt;
&lt;p&gt;The changes to &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout#Where-are-the-digits&quot;&gt;the num layer&lt;/a&gt; are again to mirror the changes to the base layer.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/t-34-0/num.png&quot; /&gt;
&lt;figcaption&gt;Num layer, gray keys turns of the NUMWORD temporary layer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In Vim you can type &lt;code&gt;20k&lt;/code&gt; or &lt;code&gt;13j&lt;/code&gt; to move up 20 lines or down 13 lines. Having the number layer turn off after &lt;code&gt;k&lt;/code&gt; or &lt;code&gt;j&lt;/code&gt; is therefore very convenient. &lt;code&gt;x&lt;/code&gt; does not turn off the layer, so you can easily type &lt;code&gt;800x600&lt;/code&gt; or similar.&lt;/p&gt;
&lt;p&gt;I won’t list it here, but &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; are also moved in the &lt;a href=&quot;/blog/2021/06/03/the-t-34-keyboard-layout#Navigation&quot;&gt;workspace nav layer&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Tap hold&lt;/h1&gt;
&lt;p&gt;I am a happy &lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot;&gt;auto shift&lt;/a&gt; user, where you hold down a key until the shifted variant appears. While I use the &lt;a href=&quot;https://github.com/qmk/qmk_firmware/&quot;&gt;qmk&lt;/a&gt; firmware, I have my own “tap hold” implementation with some extra features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Variable per-key timing.&lt;/p&gt;
&lt;p&gt;The standard implementation has one timing for all keys, which I found was super annoying as my pinkies are slow—leading to a high timeout setting to avoid accidental shifts—but then shifting would be annoyingly slow with the other faster fingers.&lt;/p&gt;
&lt;p&gt;Right now I use a 100 ms timeout for the index and middle finger, but a 135 ms timeout for the pinkies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The other big feature is a customizable hold action.&lt;/p&gt;
&lt;p&gt;While auto shift only shifts the underlying keycode, you could send whatever you want. I currently use it to simplify the input of some programming constructs:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tap&lt;/th&gt;&lt;th&gt;Hold&lt;/th&gt;&lt;th&gt; &lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;|&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt; || &lt;/code&gt;&lt;/td&gt;&lt;td&gt;One hold saves 4 key strokes for these common operators&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt; &amp;amp;&amp;amp; &lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt; == &lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;!&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt; != &lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;@u&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Vim: Execute macro stored in &lt;code&gt;u&lt;/code&gt; (matching the &lt;code&gt;qu&lt;/code&gt; combo)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{:?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Rust debug print&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{:#?}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Rust debug pretty print&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;%{}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A map in Elixir&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;(I previously used this feature only to input double or triple symbols.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Interopability with CAPSWORD/NUMWORD, &lt;code&gt;Repeat&lt;/code&gt; and the ability to shift &lt;code&gt;åäö&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;What do I dislike?&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt; is in &lt;em&gt;the&lt;/em&gt; worst spot on the keyboard, and it’s not that rare to deserve such a bad position. (In fact I might ditch that key position completely, as it’s the only position I have to move my entire hand to reach.)&lt;/li&gt;
&lt;li&gt;Having &lt;code&gt;space&lt;/code&gt; combo all symbols is a bit weird as the left mod only covers symbols on the right side, and it messes up my head. I’m considering to change so that &lt;code&gt;space&lt;/code&gt; + key on the left = number and &lt;code&gt;space&lt;/code&gt; + key on the right = symbol, and the reverse for &lt;code&gt;e&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Repeat&lt;/code&gt; being on the same column as &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; isn’t ideal. The next thing I’m going to try is turning a &lt;code&gt;Repeat&lt;/code&gt; &lt;code&gt;u&lt;/code&gt; roll into &lt;code&gt;Repeat&lt;/code&gt; &lt;code&gt;a&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;!&lt;/code&gt; combo is a bit awkward as the index and thumb come very close together.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And now, with this post out of the way, I can start the next round of experimentation.&lt;/p&gt;
&lt;p&gt;If you’re interested, the &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/ferris/keymaps/treeman&quot;&gt;QMK code is on Codeberg&lt;/a&gt; (now using the 34-key Ferris).&lt;/p&gt;
</content></entry><entry><title>The T-34 keyboard layout</title><id>http://jonashietala.se/blog/2021/06/03/the-t-34-keyboard-layout/index.html</id><updated>2026-04-27T10:16:38+00:00</updated><link href="https://www.jonashietala.se/blog/2021/06/03/the-t-34-keyboard-layout" rel="alternate"/><published>2021-06-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;A couple of months ago I started looking into ergonomical keyboards; mainly split keyboards with much fewer keys, like the &lt;a href=&quot;https://www.gboards.ca/product/gergoplex&quot; title=&quot;GergoPlex&quot;&gt;36-key Gergoplex&lt;/a&gt; and the &lt;a href=&quot;https://splitkb.com/products/kyria-pcb-kit&quot; title=&quot;Kyria PCB Kit&quot;&gt;44-key Kyria&lt;/a&gt;. I may write another post about the reasons why, but long story short I started getting pain in my thumbs, fingers, wrist and forearm, and I thought it was time to do something about it.&lt;/p&gt;
&lt;p&gt;Because my new shiny layout has been unchanged for more than a week, I’ve clearly found my Ultimate Layout™ and it’s time to immortalize it with a blog post!&lt;/p&gt;
&lt;p&gt;… Best get comfortable, this is a long post.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/T-3457-prototype-side.png&quot;&gt;
&lt;figcaption&gt;T-34/57 prototype. Because any self-respecting layout needs a name—and tanks are awesome.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;(To be completely transparent, I’ve made a few changes to it during the time it has taken me to write this post. And I’m sure, the tweaking will never stop.)&lt;/p&gt;
&lt;section id=&quot;The-journey-is-long-and-full-of-peril&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-journey-is-long-and-full-of-peril&quot; class=&quot;heading-ref&quot;&gt;The journey is long and full of peril&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you start looking at it, there are &lt;strong&gt;&lt;strong&gt;tons&lt;/strong&gt;&lt;/strong&gt; of good and interesting layouts. For example &lt;a href=&quot;https://en.wikipedia.org/wiki/Dvorak_keyboard_layout&quot; title=&quot;Dvorak keyboard layout&quot;&gt;Dvorak&lt;/a&gt;, &lt;a href=&quot;https://workmanlayout.org/&quot; title=&quot;Workman keyboard layout&quot;&gt;Workman&lt;/a&gt;, &lt;a href=&quot;https://colemakmods.github.io/mod-dh/&quot; title=&quot;Colemak Mod-DH keyboard layout&quot;&gt;Colemak Mod-DH&lt;/a&gt;, &lt;a href=&quot;https://sites.google.com/alanreiser.com/handsdown&quot; title=&quot;Hands Down keyboard layout&quot;&gt;Hands Down&lt;/a&gt;, &lt;a href=&quot;https://mathematicalmulticore.wordpress.com/the-keyboard-layout-project/&quot; title=&quot;MTGAP 2.0 keyboard layout&quot;&gt;MTGAP 2.0&lt;/a&gt;, BEAKL (many variants) and many others…&lt;/p&gt;
&lt;p&gt;They all have their pros and cons, and which one you prefer is highly subjective. At first I chose &lt;a href=&quot;https://deskthority.net/wiki/BEAKL#BEAKL_15&quot; title=&quot;BEAKL 15 keyboard layout&quot;&gt;BEAKL 15&lt;/a&gt;, mostly because I liked the discussion on the now defunct BEAKL forums, and I had some strain on my right pinky that I wanted to minimize.&lt;/p&gt;
&lt;p&gt;Although the layout felt much better than QWERTY, after trying out a bunch of modifications, I’ve since moved away from BEAKL. At around 50 WPM I got increasingly annoyed at the high same finger usage (called SFU) and I found that I wanted to use my pinkies more than BEAKL was designed for, which could be used to address the high SFU.&lt;/p&gt;
&lt;p&gt;The breaking point came when I read an article about the benefits of &lt;a href=&quot;https://precondition.github.io/pressing-e-with-the-thumb&quot; title=&quot;Pressing E with the thumb&quot;&gt;E on one of the thumb keys&lt;/a&gt;, which made me abandon BEAKL and try something else.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;My-preferences&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#My-preferences&quot; class=&quot;heading-ref&quot;&gt;My preferences&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The keymap is optimized for me and my quirks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Comfort above speed.&lt;/p&gt;
&lt;p&gt;For me I can comfortably reach 34 keys (2 thumb keys per hand), and I use very light choc keys that makes combos very comfortable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Minimize pinky movement.&lt;/p&gt;
&lt;p&gt;I’ve always used my ring finger to press keys above the home-row pinky. Maybe I have short pinkies, I dunno. It’s also why I use a 5-column layout instead of a 6-column layout.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optimized for programming and Vim usage.&lt;/p&gt;
&lt;p&gt;A vast majority of time is spent programming in Vim.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I type mostly English, but it should work well with Swedish too.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I find it hard to put it in numbers how difficult/easy I think certain keys are, but it’s &lt;strong&gt;something&lt;/strong&gt; like this:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/effort.png&quot;&gt;
&lt;figcaption&gt;A relative effort grid, lower is better. Right pinky and thumb have a bit of RSI.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;My RSI isn’t that inhibiting. Just going down to 5 columns and two thumb keys fixes most of my issues. Pressing the top outer keys with the ring finger feels good.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Some-armchair-analysis&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Some-armchair-analysis&quot; class=&quot;heading-ref&quot;&gt;Some armchair analysis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Because it gives you the illusion that the layout is backed by science.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/science.jpg&quot;&gt;
&lt;figcaption&gt;God I miss the show
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;section id=&quot;Symbols&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Symbols&quot; class=&quot;heading-ref&quot;&gt;Symbols&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The problem with trying to optimize for programming is that it varies &lt;strong&gt;a lot&lt;/strong&gt; depending on the language.&lt;/p&gt;
&lt;p&gt;Take for example three of my own projects: a WIP Rust implementation of Git (following the excellent Building Git), a crypto payment processor in Elixir, and the &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies&quot;&gt;source code for my book&lt;/a&gt; (mostly English, but with some Racket and other codey things):&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/combined-symbol-freq.svg&quot;&gt;
&lt;figcaption&gt;Symbol frequencies from a Rust, an Elixir and a book project.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;While there’s a general trend here, we see some massive outliers. Like how &lt;code&gt;-&lt;/code&gt; is incredibly overrepresented in the book’s source (because the Racket convention is &lt;code&gt;kebab-case&lt;/code&gt; and I use &lt;code&gt;---&lt;/code&gt; to represent an em dash &lt;code&gt;—&lt;/code&gt;) or how &lt;code&gt;;&lt;/code&gt; is very common in Rust but almost non-existent in Elixir.&lt;/p&gt;
&lt;p&gt;What should we do then? We can try a keylogger to see what symbols we’re typing. Here’s the results, together with a dataset of all my personal projects I could find (labeled “Code”):&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/code-key-freq.svg&quot;&gt;
&lt;figcaption&gt;Symbol frequencies during a keylog session and from a random collection of personal projects (mostly in C++).
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It’s not perfect either, as I didn’t run the keylog as long as I should, and I only used a small selection of languages at that time.  The big outliers that come from Vim are &lt;code&gt;:&lt;/code&gt; (I save a lot with &lt;code&gt;:w&lt;/code&gt;), &lt;code&gt;.&lt;/code&gt; (repeat last action), &lt;code&gt;/&lt;/code&gt; (regex search) and &lt;code&gt;$&lt;/code&gt; (end-of-line). I don’t know why &lt;code&gt;&apos;&lt;/code&gt; is overrepresented in the keylog, it’s not something I use a lot in Vim.&lt;/p&gt;
&lt;p&gt;One might wonder, where do the symbols appear? Are they mostly next to characters, or next to other symbols? Here’s a table of where the symbols end up, and what symbol bigrams they appear (ignoring double symbols like &lt;code&gt;||&lt;/code&gt;), using the Code source:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Char&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;th&gt;Next to letter&lt;/th&gt;
&lt;th&gt;Next to symbol&lt;/th&gt;
&lt;th&gt;Common bigrams&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;,&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;220930&lt;/td&gt;
&lt;td&gt;31.22%&lt;/td&gt;
&lt;td&gt;12.23%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;),&lt;/code&gt; &lt;code&gt;&quot;,&lt;/code&gt; &lt;code&gt;},&lt;/code&gt; &lt;code&gt;],&lt;/code&gt; &lt;code&gt;_,&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;169048&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;86.21%&lt;/strong&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.89%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_,&lt;/code&gt; &lt;code&gt;(_&lt;/code&gt; &lt;code&gt;_}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;158614&lt;/td&gt;
&lt;td&gt;24.11%&lt;/td&gt;
&lt;td&gt;29.00%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;);&lt;/code&gt; &lt;code&gt;()&lt;/code&gt; &lt;code&gt;),&lt;/code&gt; &lt;code&gt;&quot;)&lt;/code&gt; &lt;code&gt;])&lt;/code&gt; &lt;code&gt;})&lt;/code&gt; &lt;code&gt;)}&lt;/code&gt; &lt;code&gt;).&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;158598&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;66.06%&lt;/strong&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;19.71%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;()&lt;/code&gt; &lt;code&gt;(&quot;&lt;/code&gt; &lt;code&gt;(:&lt;/code&gt; &lt;code&gt;!(&lt;/code&gt; &lt;code&gt;(&amp;amp;&lt;/code&gt; &lt;code&gt;(%&lt;/code&gt; &lt;code&gt;?(&lt;/code&gt; &lt;code&gt;({&lt;/code&gt; &lt;code&gt;([&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;132580&lt;/td&gt;
&lt;td&gt;43.62%&lt;/td&gt;
&lt;td&gt;12.95%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{:&lt;/code&gt; &lt;code&gt;(:&lt;/code&gt; &lt;code&gt;:/&lt;/code&gt; &lt;code&gt;`:&lt;/code&gt; &lt;code&gt;[:&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;129818&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;72.88%&lt;/strong&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5.98%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;).&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;105618&lt;/td&gt;
&lt;td&gt;24.83%&lt;/td&gt;
&lt;td&gt;27.41%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;,&lt;/code&gt; &lt;code&gt;&quot;)&lt;/code&gt; &lt;code&gt;(&quot;&lt;/code&gt; &lt;code&gt;&quot;]&lt;/code&gt; &lt;code&gt;&quot;%&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;73090&lt;/td&gt;
&lt;td&gt;1.95%&lt;/td&gt;
&lt;td&gt;13.92%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;=&lt;/code&gt; &lt;code&gt;&amp;gt;=&lt;/code&gt; &lt;code&gt;=&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;69068&lt;/td&gt;
&lt;td&gt;23.20%&lt;/td&gt;
&lt;td&gt;28.68%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{:&lt;/code&gt; &lt;code&gt;%{&lt;/code&gt; &lt;code&gt;#{&lt;/code&gt; &lt;code&gt;]{&lt;/code&gt; &lt;code&gt;{}&lt;/code&gt; &lt;code&gt;({&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;69060&lt;/td&gt;
&lt;td&gt;20.28%&lt;/td&gt;
&lt;td&gt;24.41%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;},&lt;/code&gt; &lt;code&gt;})&lt;/code&gt; &lt;code&gt;)}&lt;/code&gt; &lt;code&gt;{}&lt;/code&gt; &lt;code&gt;]}&lt;/code&gt; &lt;code&gt;_}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;67076&lt;/td&gt;
&lt;td&gt;37.11%&lt;/td&gt;
&lt;td&gt;13.43%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;55914&lt;/td&gt;
&lt;td&gt;17.22%&lt;/td&gt;
&lt;td&gt;24.83%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;);&lt;/code&gt; &lt;code&gt;];&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;54178&lt;/td&gt;
&lt;td&gt;15.33%&lt;/td&gt;
&lt;td&gt;33.62%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt; &lt;code&gt;|&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;gt;=&lt;/code&gt; &lt;code&gt;=&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;49296&lt;/td&gt;
&lt;td&gt;36.72%&lt;/td&gt;
&lt;td&gt;10.94%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;44042&lt;/td&gt;
&lt;td&gt;46.64%&lt;/td&gt;
&lt;td&gt;28.06%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[]&lt;/code&gt; &lt;code&gt;][&lt;/code&gt; &lt;code&gt;[:&lt;/code&gt; &lt;code&gt;([&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;43998&lt;/td&gt;
&lt;td&gt;28.92%&lt;/td&gt;
&lt;td&gt;48.22%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;],&lt;/code&gt; &lt;code&gt;[]&lt;/code&gt; &lt;code&gt;])&lt;/code&gt; &lt;code&gt;][&lt;/code&gt; &lt;code&gt;]{&lt;/code&gt; &lt;code&gt;]}&lt;/code&gt; &lt;code&gt;&quot;]&lt;/code&gt; &lt;code&gt;];&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;35456&lt;/td&gt;
&lt;td&gt;12.57%&lt;/td&gt;
&lt;td&gt;17.64%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#{&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32828&lt;/td&gt;
&lt;td&gt;31.43%&lt;/td&gt;
&lt;td&gt;19.31%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;`&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;29158&lt;/td&gt;
&lt;td&gt;27.60%&lt;/td&gt;
&lt;td&gt;20.64%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;`: &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&apos;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;18572&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;strong&gt;70.55%&lt;/strong&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15.70%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;|&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;17820&lt;/td&gt;
&lt;td&gt;3.69%&lt;/td&gt;
&lt;td&gt;21.87%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;|&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;17736&lt;/td&gt;
&lt;td&gt;14.71%&lt;/td&gt;
&lt;td&gt;6.87%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16712&lt;/td&gt;
&lt;td&gt;22.64%&lt;/td&gt;
&lt;td&gt;24.49%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;?(&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16660&lt;/td&gt;
&lt;td&gt;26.81%&lt;/td&gt;
&lt;td&gt;39.81%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%{&lt;/code&gt; &lt;code&gt;(%&lt;/code&gt; &lt;code&gt;&quot;%&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;15068&lt;/td&gt;
&lt;td&gt;28.36%&lt;/td&gt;
&lt;td&gt;16.44%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(&amp;amp;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;14076&lt;/td&gt;
&lt;td&gt;48.70%&lt;/td&gt;
&lt;td&gt;5.52%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;13896&lt;/td&gt;
&lt;td&gt;13.02%&lt;/td&gt;
&lt;td&gt;14.72%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10236&lt;/td&gt;
&lt;td&gt;35.55%&lt;/td&gt;
&lt;td&gt;29.35%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;9812&lt;/td&gt;
&lt;td&gt;34.80%&lt;/td&gt;
&lt;td&gt;40.13%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;!(&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4226&lt;/td&gt;
&lt;td&gt;36.63%&lt;/td&gt;
&lt;td&gt;25.01%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;~&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2596&lt;/td&gt;
&lt;td&gt;32.16%&lt;/td&gt;
&lt;td&gt;17.41%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1436&lt;/td&gt;
&lt;td&gt;24.23%&lt;/td&gt;
&lt;td&gt;41.23%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Note that it it tracks letters on both sides of the symbol, which is why &lt;code&gt;,&lt;/code&gt; is only next to a letter 31% of the time (it’s almost always next to a space).&lt;/p&gt;
&lt;p&gt;And a plot of how common the bigrams themselves are:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/bigram-freq.svg&quot;&gt;
&lt;figcaption&gt;Symbol bigrams, for bigrams seen over 1000 times
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;So what observations can we draw from this imperfect dataset? Here are some thoughts I have:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Parens &lt;code&gt;(&lt;/code&gt; &lt;code&gt;)&lt;/code&gt; are very common. I’d expect it if it was Lisp, but they seem very common even in Rust. They’re also neighbours with many other symbols, making them a high priority.
&lt;/li&gt;
&lt;li&gt;
The symbols &lt;code&gt;_&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;&apos;&lt;/code&gt; are almost always next to an alpha character, meaning they don’t have to be placed next to other symbols, and can be optimized to be easily reachable from the base layer. I’ll add &lt;code&gt;,&lt;/code&gt; to this class as well.
&lt;/li&gt;
&lt;li&gt;
Brackets &lt;code&gt;{&lt;/code&gt; &lt;code&gt;}&lt;/code&gt; and &lt;code&gt;[&lt;/code&gt; &lt;code&gt;]&lt;/code&gt; aren’t super common, but they do combine with many other symbols (mostly other types of brackets). If &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; are used in a symbol bigram then it’s mostly in arrow form, like &lt;code&gt;-&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;gt;=&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Computation symbols like &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt; are mostly surrounded by space, and they’re less used than I would’ve thought.
&lt;/li&gt;
&lt;li&gt;
Interestingly, &lt;code&gt;&quot;&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt; have traditionally been on a shift layer, but here they’re much more common than their counterparts &lt;code&gt;&apos;&lt;/code&gt; and &lt;code&gt;-&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Digits&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Digits&quot; class=&quot;heading-ref&quot;&gt;Digits&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Typically digits follow &lt;a href=&quot;https://en.wikipedia.org/wiki/Benford%27s_law&quot; title=&quot;Benford&apos;s law&quot;&gt;Benford’s law&lt;/a&gt; that says that lower numbers are more common. How does that hold up for us?&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/combined-digit-freq.svg&quot;&gt;
&lt;figcaption&gt;Digit frequencies
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Fairly well I’d say. Again, the keylog displays some different results, mainly because I tend to use workspaces &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;8&lt;/code&gt; and &lt;code&gt;9&lt;/code&gt; more on a traditional keyboard (accessed with &lt;code&gt;Gui&lt;/code&gt; + number). This can be ignored when designing the layout as I can use whatever digit is convenient.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Letters&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Letters&quot; class=&quot;heading-ref&quot;&gt;Letters&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/combined-se-en-letter-freq.svg&quot;&gt;
&lt;figcaption&gt;Letter frequencies from the code and keylog corpus, and a large English and Swedish dataset
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Optimizing letters is an area where layouts have focused a lot of attention on. Some notes from my own data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Code basically follows English, which makes sense as you’re mostly typing English words.
&lt;/li&gt;
&lt;li&gt;
There are some differences with Swedish, most notably &lt;code&gt;k&lt;/code&gt; and &lt;code&gt;r&lt;/code&gt; are more common (and some extra vowels of course).
&lt;/li&gt;
&lt;li&gt;
My Vim usage makes some unusual keys quite common. Apparently I’m a &lt;code&gt;j&lt;/code&gt;/&lt;code&gt;k&lt;/code&gt; spammer (up/down)—which isn’t a good habit to have as there are more efficient ways to move vertically. &lt;code&gt;w&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; (forward and backwards a word) and &lt;code&gt;:w&lt;/code&gt; (save) are used a lot. I also seem to mistype a bunch as &lt;code&gt;u&lt;/code&gt; is very common (undo).
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On one hand you might want to place these keys in better positions, but on the other hand they’re often typed with a pause, after I’ve had time to think for a second or two, so it might not be important enough to warp the entire layout.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;The-layout&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-layout&quot; class=&quot;heading-ref&quot;&gt;The layout&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On to the actual layout then. Illustrations are inspired by &lt;a href=&quot;http://thedarnedestthing.com/daily%20beakl&quot; title=&quot;Daily Beakl&quot;&gt;the darnedest thing&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/legend.png&quot;&gt;
&lt;figcaption&gt;Legend
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;section id=&quot;Base-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Base-layer&quot; class=&quot;heading-ref&quot;&gt;Base layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/base.png&quot;&gt;
&lt;figcaption&gt;Base layer
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There are two different ways you can make decisions: you either take a strictly logical approach, using the left half of your brain, or you let your subconscious decide as you go by feeling, letting the right half of your brain run the show.&lt;/p&gt;
&lt;p&gt;It’s common to use a program to optimize the layout, letting the computer explore tons of layouts very quickly. I did not go this route, as I found it difficult to write down my exact preferences. Instead I based my layout on &lt;a href=&quot;https://xsznix.wordpress.com/2016/05/16/introducing-the-rsthd-layout/&quot; title=&quot;RSTHD keyboard layout&quot;&gt;RSTHD&lt;/a&gt;, which is a well optimized layout, and tweaked it whenever I ran into things that annoyed me.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Feel the force!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Yoda
&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;p&gt;These are the most notable changes I’ve made to RSTHD:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;e&lt;/code&gt; on other thumb. Feels much better to avoid having “here”, “there” and similar combinations on the same hand.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;q&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt; moved away to combos in favor of more symbols.
&lt;/li&gt;
&lt;li&gt;
Swap &lt;code&gt;d&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; as I dislike the center column and lower index is good.
&lt;/li&gt;
&lt;li&gt;
Swap &lt;code&gt;l&lt;/code&gt; and &lt;code&gt;w&lt;/code&gt; to place &lt;code&gt;l&lt;/code&gt; on that good lower index.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;k&lt;/code&gt; is in a better spot as it’s much more common in Swedish, and I use it a lot with Vim. As a bonus it makes &lt;code&gt;ck&lt;/code&gt; very nice to type, again common in Swedish.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I &lt;strong&gt;really&lt;/strong&gt; like &lt;code&gt;e&lt;/code&gt; on the thumb and I don’t think I’ll ever want to give it up. The low SFU and the consonant/vowel separations also feels very good to me.&lt;/p&gt;
&lt;p&gt;And the rationale for choosing the symbols:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt; some of the most common symbols, so they got prime real estate that let’s me type &lt;code&gt;()&lt;/code&gt; quickly. As a bonus I can use them as a prefix for a lot of things in Vim. For instance &lt;code&gt;)d&lt;/code&gt; (next LSP diagnostics), &lt;code&gt;)q&lt;/code&gt; (next quickfix) and &lt;code&gt;)s&lt;/code&gt; (next spellcheck error). (Nah, I never used &lt;code&gt;()&lt;/code&gt; for their original purpose.)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_&lt;/code&gt; is also very common, and is almost always next to letters in &lt;code&gt;snake_case&lt;/code&gt;, so having it on base is awesome. And it doubles as a Vim prefix, for example &lt;code&gt;_d&lt;/code&gt; (goto definition) and &lt;code&gt;_h&lt;/code&gt; (show help of thing under cursor).
&lt;/li&gt;
&lt;li&gt;
Which of &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt; to prioritize is a good question. I put &lt;code&gt;.&lt;/code&gt; in a better position as it’s used as “repeat last action” in Vim.
&lt;/li&gt;
&lt;li&gt;
Some of the most common symbols that don’t usually stand next to other symbols are moved to home-row combos. I find they’re easier to type than moving my fingers off home-row, so &lt;code&gt;:&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;&apos;&lt;/code&gt;, and &lt;code&gt;;&lt;/code&gt; were moved off base.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&quot;&lt;/code&gt; is very common. I’ve also had &lt;code&gt;/&lt;/code&gt; here, but I haven’t fully decided which I prefer yet.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;=&lt;/code&gt; is on base as it makes &lt;code&gt; = &lt;/code&gt; very comfortable, which is the primary usage for it. It also makes it easy to pair with the different symbols, such as &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;~&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This feels quite good—especially &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Combos&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Combos&quot; class=&quot;heading-ref&quot;&gt;Combos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A combo (sometimes called a chord) is when you press down two keys at the same time to produce something else. For instance if I press &lt;code&gt;c&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; at the same time I get &lt;code&gt;q&lt;/code&gt;. With the light choc switches I use this feels very nice, even pressing three keys or vertical combos with two keys using a single finger.&lt;/p&gt;
&lt;p&gt;I use it for lots of things. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Hide the least common chars &lt;code&gt;q&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
“Big keys” on home-row: &lt;code&gt;Tab&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt; and &lt;code&gt;Escape&lt;/code&gt; (perfect for Vim!).
&lt;/li&gt;
&lt;li&gt;
Delete things: &lt;code&gt;Delete&lt;/code&gt; and &lt;code&gt;Backspace&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Symbols like &lt;code&gt;:&lt;/code&gt;, &lt;code&gt;&apos;&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
Special things, like saving in Vim (&lt;code&gt;:wq&amp;lt;br&amp;gt;&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s a table (because I wasn’t happy with the visualization I tried to make):&lt;/p&gt;
&lt;hr&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Top Left&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Res&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Top Right&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Res&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;c&lt;/code&gt; + &lt;code&gt;k&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;x&lt;/code&gt; + &lt;code&gt;w&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;#{ ↓ }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;  &lt;code&gt;k&lt;/code&gt; + &lt;code&gt;f&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;z&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;    &lt;code&gt;,&lt;/code&gt; + &lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Backspace&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;c&lt;/code&gt; + &lt;code&gt;k&lt;/code&gt; + &lt;code&gt;f&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Delete&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;  &lt;code&gt;w&lt;/code&gt; + &lt;code&gt;,&lt;/code&gt; + &lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Ctrl + W&lt;/code&gt; (backspace word)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Home Left  &lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Res  &lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Home Right  &lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Res&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;  &lt;code&gt;t&lt;/code&gt; + &lt;code&gt;h&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Escape&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;n&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;:&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;s&lt;/code&gt; + &lt;code&gt;t&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Tab&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;  &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;i&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;s&lt;/code&gt; +   &lt;code&gt;h&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;n&lt;/code&gt; +   &lt;code&gt;i&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;&apos;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;s&lt;/code&gt; + &lt;code&gt;t&lt;/code&gt; + &lt;code&gt;h&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;n&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;i&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Vim save&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Bottom Left    &lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Res    &lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Bottom Right    &lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Res&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;v&lt;/code&gt; + &lt;code&gt;g&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Vim vsplit&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;(&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;  &lt;code&gt;(&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;v&lt;/code&gt; + &lt;code&gt;g&lt;/code&gt; + &lt;code&gt;p&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Vim close&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;l&lt;/code&gt; + &lt;code&gt;(&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Swedish layer&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Mixed&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Res&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;t&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; (left + right ring)&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;CAPSWORD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;Space&lt;/code&gt; + &lt;code&gt;e&lt;/code&gt; (left + right thumb)&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;NUMWORD&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;The rationale here is that home-row combos are very easy to type, so the common keys like &lt;code&gt;Enter&lt;/code&gt; and &lt;code&gt;:&lt;/code&gt; go there. Split combos with the index and ring finger are slightly more awkward to type, but still good.&lt;/p&gt;
&lt;p&gt;Having related functionality close to each other makes it a little easier to learn, so &lt;code&gt;^&lt;/code&gt; (goto first non-space char in line) and &lt;code&gt;$&lt;/code&gt; (goto last char in line) pairs nicely. They, and the other combo-able symbols, are mostly stand-alone so there’s minimal switching between layers to type them.&lt;/p&gt;
&lt;p&gt;There are also vertical combos with the common arrow combinations you often see in programming:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/sym-combo.png&quot;&gt;
&lt;figcaption&gt;Vertical symbol combos
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Depending on the language, symbols like &lt;code&gt;&amp;gt;=&lt;/code&gt;, &lt;code&gt;=&amp;gt;&lt;/code&gt;, &lt;code&gt;|&amp;gt;&lt;/code&gt; and &lt;code&gt;-&amp;gt;&lt;/code&gt; are common, but often difficult to type. Combos solve this really well.&lt;/p&gt;
&lt;p&gt;Also, splitting windows in vim is something I do a lot. Horizontal/vertical splits are laid out to match the split direction, and they’re grouped next to closing a window. (Why is saving vim on the right side then? Because &lt;code&gt;);&lt;/code&gt; is very common. It’s not perfect I know.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;What-about-shift&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#What-about-shift&quot; class=&quot;heading-ref&quot;&gt;What about shift?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Where to place shift was one of the most difficult decisions for me. I considered these options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href=&quot;https://docs.qmk.fm/#/one_shot_keys&quot; title=&quot;One shot keys&quot;&gt;One-shot shift&lt;/a&gt;, where you press and release shift and the next letter will be shifted, is great. But it doesn’t vibe well with &lt;code&gt;e&lt;/code&gt; on the thumb (and no outer column).
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://precondition.github.io/home-row-mods&quot; title=&quot;Home row mods&quot;&gt;Home-row mods&lt;/a&gt;, where you press and hold a regular key to turn it into shift. Many people love it, but I found it difficult to coordinate between left/right (as you often want to hold with the opposite hand).
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://docs.qmk.fm/#/feature_auto_shift&quot; title=&quot;Auto shift&quot;&gt;Auto Shift&lt;/a&gt;, where you just do a long press to get an uppercase letter. It’s convenient for single letters, but many people who have tried it says it messed up their rhythm.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wanted to use one-shot shift, but I just couldn’t get it to work well with &lt;code&gt;e&lt;/code&gt; on the thumb. I got the fiddly home-row config to work, and I think I could learn to live with it, but for me auto shift felt better.&lt;/p&gt;
&lt;p&gt;Sure, it’s harder to type quickly with auto shift, but I want to maximize comfort over speed, and auto shift feels like the option requiring the least amount of effort. I do have one-shot shift keys, but on a separate layer, which I use for some shortcuts (more on that shortly).&lt;/p&gt;
&lt;p&gt;Typing multiple uppercase letters in a row does suck. That’s why I also use “CAPSWORD”, which is a smart caps lock that turns itself off after space or some other special characters. It makes it super easy to type variables like &lt;code&gt;POST_LIMIT&lt;/code&gt; for example.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Mods-symbols&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Mods-symbols&quot; class=&quot;heading-ref&quot;&gt;Mods &amp;amp; symbols&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I have modifiers combined with the other symbols, across two layers:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/lmod.png&quot;&gt;
&lt;figcaption&gt;Press left button for mods on the left and symbols on the right
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/rmod.png&quot;&gt;
&lt;figcaption&gt;Press right button for mods on the right and symbols on the left
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Instead of home-row mods, I have mods on a separate layer. (Some refer to it as &lt;a href=&quot;https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum#oneshot-modifiers&quot; title=&quot;Callum Oakley keymap&quot;&gt;callum-style mods&lt;/a&gt;, from the person who invented/popularized it.) While you need to press one key extra to access &lt;code&gt;Ctrl&lt;/code&gt; for instance, there are no timings here so it’s very quick and it feels surprisingly good.  I’ve kept same-side mod activation because that’s what I started with, and I don’t feel a need to change it.&lt;/p&gt;
&lt;p&gt;Some shortcuts, like &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt;, are impossible to press left-handed (when I use the mouse/trackball), so I’ve added them here.&lt;/p&gt;
&lt;p&gt;I tried to place the symbols ordered by frequency, in some kind of logical groupings. There are very few symbol bigrams I have trouble typing. I find it’s mostly holding down &lt;code&gt;LMOD&lt;/code&gt; to type &lt;code&gt;[]&lt;/code&gt; or similar. I’ve also kept the position of the symbols from base layer, so I don’t have to switch layers if I type bigrams like &lt;code&gt;](&lt;/code&gt; (but truthfully, it almost never comes up).&lt;/p&gt;
&lt;p&gt;While I can use the layer switches as one-shot for the symbols, I also have combos with &lt;code&gt;Space&lt;/code&gt; + &lt;code&gt;&amp;lt;key&amp;gt;&lt;/code&gt; to produce symbols from the base layer, for example &lt;code&gt;Space&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; = &lt;code&gt;[&lt;/code&gt;. I now use that exclusively, and relegate the layer switch for the symbol bigrams (because I dislike having to move the thumb).&lt;/p&gt;
&lt;p&gt;One last annoyance is double- or triple-tapping symbols, particularly with the pinky, for things like &lt;code&gt;||&lt;/code&gt;. I got around it by adding long press for them, similar to what auto shift does:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Tap&lt;/th&gt;
&lt;th style=&quot;text-align: left;&quot;&gt;Long press&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;|&lt;/code&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;+&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;_&lt;/code&gt; &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;\&lt;/code&gt; &lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Double symbol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;code&gt;&quot;&lt;/code&gt; &lt;code&gt;&apos;&lt;/code&gt; &lt;code&gt;=&lt;/code&gt; &lt;code&gt;`&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;Triple symbol&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section id=&quot;Where-are-the-digits&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Where-are-the-digits&quot; class=&quot;heading-ref&quot;&gt;Where are the digits?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here they are:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/num.png&quot;&gt;
&lt;figcaption&gt;Num layer, the dark gray keys turns off NUMWORD
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Yupp, I use numbers on home-row (and the low index, which is the next best key apart from the thumbs). They’re laid out prioritizing lower digits, slightly de-emphasizing index fingers as they’re responsible for two digits. Separating even from odd numbers made sense from an optimization aspect, but it also made it easier to learn.&lt;/p&gt;
&lt;p&gt;What makes this special is that the layer switch is smart, similar to CAPSWORD as the layer turns off on space (which I call NUMWORD). So if I want to write 
&lt;code class=&quot;highlight elixir&quot;&gt;&lt;span class=&quot;keyword control elixir&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;keyword operator comparison elixir&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;constant numeric elixir&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword control elixir&quot;&gt;do&lt;/span&gt;&lt;/code&gt; then I type &lt;code&gt;if x == &amp;lt;NUMWORD&amp;gt;3 do&lt;/code&gt; and the layer turns off after the space.&lt;/p&gt;
&lt;p&gt;What about &lt;code&gt;k&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;G&lt;/code&gt;? Those are for easy navigation with Vim. So &lt;code&gt;13k&lt;/code&gt; means “13 lines above” and &lt;code&gt;127G&lt;/code&gt; means “line number 127”. Naturally, the layer turns itself off, so it doesn’t interfere with my next commands. I use it all the time and it’s fantastic.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Navigation&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Navigation&quot; class=&quot;heading-ref&quot;&gt;Navigation&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/nav.png&quot;&gt;
&lt;figcaption&gt;Navigation, both two handed and one-handed
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Navigation is the only “hold key down” I have. Vim-like arrows on the right side (but I try not to use them in Vim, as jumping with the NUM layer is more efficient). &lt;code&gt;Ctrl&lt;/code&gt; + arrow is used to switch windows in Vim and &lt;code&gt;Gui&lt;/code&gt; + &lt;code&gt;w&lt;/code&gt;/&lt;code&gt;e&lt;/code&gt;/&lt;code&gt;r&lt;/code&gt; switches between my three monitors (it’s here because it’s so common).&lt;/p&gt;
&lt;p&gt;Navigation on the left hand is great when I have the right hand on the mouse; initially I didn’t have arrows here, but I found myself missing them. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Tab&lt;/code&gt; and &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;Tab&lt;/code&gt; switches tabs in Firefox.&lt;/p&gt;
&lt;p&gt;I also have a workspace navigation layer, used exclusively for workspace manipulation:&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/wnav.png&quot;&gt;
&lt;figcaption&gt;Workspace nav layer. All keys have &lt;code&gt;Gui&lt;/code&gt; implicit.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;Gui&lt;/code&gt; + number switches to that workspace; &lt;code&gt;Gui&lt;/code&gt; + &lt;code&gt;k&lt;/code&gt;/&lt;code&gt;j&lt;/code&gt; switches between windows; and if you &lt;code&gt;Shift&lt;/code&gt; (long press) you move the current window there.&lt;/p&gt;
&lt;p&gt;Having a separate layer for this isn’t strictly needed, but it feels much more convenient.  I tried the regular one-shot mods and home-row mods on the number layer, but I just didn’t like it that much. I also tried a smart layer or a simple layer switch (where I had to exit the layer explicitly), but I prefer having to hold down a key so I know that I’m in the workspace layer.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Function-layer&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Function-layer&quot; class=&quot;heading-ref&quot;&gt;Function layer&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/fun.png&quot;&gt;
&lt;figcaption&gt;Function keys
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Nothing special going on with the function keys. Having them on the same positions as numbers makes them easy to learn, which is important for me as I almost never use them.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Swedish-overlay&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Swedish-overlay&quot; class=&quot;heading-ref&quot;&gt;Swedish overlay&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/swe.png&quot;&gt;
&lt;figcaption&gt;Swedish overlay
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;As a Swede, I do type Swedish from time to time. But I never type code and Swedish at the same time, so it made sense to have a Swedish mode that I can toggle, for example when I need to write an email or similar.&lt;/p&gt;
&lt;p&gt;It replaces &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt;, as they’re mostly used in code, and &lt;code&gt;åäö&lt;/code&gt; are practically never used next to the vowels, making the layout very pleasant for Swedish as well. The layer is is activated with &lt;code&gt;l&lt;/code&gt; + &lt;code&gt;(&lt;/code&gt; + &lt;code&gt;)&lt;/code&gt; (and deactivated with the same keys).  I can still access the symbols with the one-shot layer on the left thumb or with combos like &lt;code&gt;Space&lt;/code&gt; + &lt;code&gt;å&lt;/code&gt; = &lt;code&gt;(&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Options&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Options&quot; class=&quot;heading-ref&quot;&gt;Options&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/opt.png&quot;&gt;
&lt;figcaption&gt;Options
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I have some runtime options I might occasionally want to access:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
On a regular keyboard and on my laptop I’ve had &lt;code&gt;Escape&lt;/code&gt; and &lt;code&gt;Caps Lock&lt;/code&gt; swapped (to make it easier to press in Vim). I can toggle it on the keyboard so I can use it there as well.
&lt;/li&gt;
&lt;li&gt;
I don’t currently have anything that differs between Windows and Linux I don’t think, but things like window switching works differently. When I go back to working on Windows I’ll probably make use of this.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NUM&lt;/code&gt; toggles a regular number layer, that don’t deactivate on &lt;code&gt;Space&lt;/code&gt;, which I  use when I practice number typing.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Specials&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Specials&quot; class=&quot;heading-ref&quot;&gt;Specials&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/t-34/spec.png&quot;&gt;
&lt;figcaption&gt;Special characters
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There’s plenty of room here for rare, but useful, symbols. Such as the arrow symbols &lt;code&gt;↑&lt;/code&gt; and dead key modifiers.&lt;/p&gt;
&lt;p&gt;The pink keys are called “dead keys”. A dead key is a sort of prefix to modify a symbol, so to type &lt;code&gt;ã&lt;/code&gt; you press &lt;code&gt;~&lt;/code&gt; (dead) + &lt;code&gt;a&lt;/code&gt;. The &lt;code&gt;^&lt;/code&gt; combo is also turned into a dead key on this layer.&lt;/p&gt;
&lt;p&gt;You might say it’s ridiculous to have this kind of layer, but I think it’s very easy to learn with the keys staying in logical positions (dead &lt;code&gt;`&lt;/code&gt; has the same position as the normal &lt;code&gt;`&lt;/code&gt; for instance).&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;34-keys-are-plenty&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#34-keys-are-plenty&quot; class=&quot;heading-ref&quot;&gt;34 keys are plenty&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you’re not into tweaking layouts it might sound crazy with only 34 keys (and maybe it is), but I still think there’s plenty of space here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
With layers you multiply your available space, making it easy to have arrows, numbers, function keys and symbols right under your fingers.
&lt;/li&gt;
&lt;li&gt;
Combos will in practice give you access to even more keys than a regular keyboard.
&lt;/li&gt;
&lt;li&gt;
Multi function keys, with long press or double clicks (which I don’t even use), combined with combos and layers gives you more available space than you’ll ever need.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I could easily fit much more functionality into my layout if I needed to. The constraint isn’t space—it’s your ability to learn and get proficient with a complex layout. (And I don’t think it’s &lt;strong&gt;that&lt;/strong&gt; hard to learn a new layout, but that’s a topic for another day.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Is-this-the-perfect-layout&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Is-this-the-perfect-layout&quot; class=&quot;heading-ref&quot;&gt;Is this the perfect layout?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Oh, that’s funny…&lt;/p&gt;
&lt;p&gt;There are always things that could be done better. Here are some things that currently annoy me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;As I press the outer top keys (&lt;code&gt;y&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt;) with my ring finger, “sys” is terrible to type as it’s three letters in a row with the same finger.&lt;/p&gt;
&lt;p&gt;I’ve tried to address this by moving &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt;, but everything I’ve tried so far has created larger problems. So maybe I’ll shove in a combo to produce “sys” and call it a day?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;bj&lt;/code&gt; is crazy annoying. It gets worse if I program in a codebase that uses &lt;code&gt;Object&lt;/code&gt; all over the place.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;j&lt;/code&gt; is in the worst spot, even though I use it a lot in Vim.&lt;/p&gt;
&lt;p&gt;Tried &lt;code&gt;j&lt;/code&gt; as combos, but I liked that even less. At first I actually used the &lt;code&gt;NAV&lt;/code&gt; layer, but I got annoyed at the extra layer switch and I had some misfiring due to timing issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I’m not 100% content with the symbols layer, and I’ll probably try to move some symbols around a bit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And there are a bunch of things that aren’t optimal, but at this point I’m hitting diminishing returns, so I’ll try to avoid changing things unless it’s something that really bothers me.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;How-did-you-implement-this&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#How-did-you-implement-this&quot; class=&quot;heading-ref&quot;&gt;How did you implement this?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I use QMK and &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware/src/branch/master/keyboards/splitkb/kyria/keymaps/treeman&quot; title=&quot;My keymap&quot;&gt;my keymap is on Codeberg&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Why Cryptocurrencies? is now available in print</title><id>http://jonashietala.se/blog/2021/05/31/why_cryptocurrencies_is_now_available_in_print/index.html</id><updated>2026-04-27T11:10:22+00:00</updated><link href="https://www.jonashietala.se/blog/2021/05/31/why_cryptocurrencies_is_now_available_in_print" rel="alternate"/><published>2021-05-31T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Today is a big milestone for me, as this marks a big milestone in the biggest personal project I’ve undertaken.&lt;/p&gt;
&lt;p&gt;My book ‘&lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;Why Cryptocurrencies?&lt;/a&gt;’ is released in print today! It’s my attempt to explain what cryptocurrencies are and what problems they solve, in a simple and approachable manner.&lt;/p&gt;
&lt;p&gt;I’ve been working on the book in the open &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies&quot;&gt;on GitHub&lt;/a&gt; and &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies/commit/5478b8a&quot;&gt;the first recorded commit&lt;/a&gt; is from Dec 19, 2018, with a chapter outline. 1237 commits later, and a bunch of work outside that, and the book is now Done™. (Only a year after my &lt;a href=&quot;/blog/2020/04/29/my_book_why_cryptocurrencies_is_done/&quot;&gt;blog post saying it was done&lt;/a&gt;…)&lt;/p&gt;
&lt;p&gt;If you want to check it out, you can &lt;a href=&quot;https://whycryptocurrencies.com/toc.html&quot;&gt;read it online for free&lt;/a&gt; or you can &lt;a href=&quot;https://whycryptocurrencies.com/#print&quot;&gt;buy&lt;/a&gt; it from wherever you buy your books.&lt;/p&gt;
&lt;h1&gt;What’s next?&lt;/h1&gt;
&lt;p&gt;I need to check the formating for the eBook, so it looks ok on as many platforms as possible. And then work on my &lt;a href=&quot;https://github.com/bitpal&quot;&gt;self-hosted payment processor&lt;/a&gt;, which I’ll use to sell the eBook on my site for crypto. (I’ll be sure to make it available on various eBook platforms too.)&lt;/p&gt;
&lt;p&gt;I’m planning to write a couple of blog posts detailing how I made the book and some lessons or tips I have for aspiring writers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2020/05/03/how_i_wrote_my_book_using_pollen/&quot;&gt;How I made an online book with Lisp&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2021/05/10/how_i_made_a_kick_ass_cover_for_my_self_published_book/&quot;&gt;How I worked with a designer to create the cover&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;How I did the interior layout for my self-published book. (planned)&lt;/li&gt;
&lt;li&gt;Converting my online book to epub. (planned)&lt;/li&gt;
&lt;li&gt;Writing lessons learned after writing a book. (planned)&lt;/li&gt;
&lt;li&gt;I self-published a book—was it worth it? (planned)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, I can finally archive the book project as done.&lt;/p&gt;
</content></entry><entry><title>How I made a kick-ass cover for my self-published book</title><id>http://jonashietala.se/blog/2021/05/10/how_i_made_a_kick_ass_cover_for_my_self_published_book/index.html</id><updated>2024-06-27T07:50:16+00:00</updated><link href="https://www.jonashietala.se/blog/2021/05/10/how_i_made_a_kick_ass_cover_for_my_self_published_book" rel="alternate"/><published>2021-05-10T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;If you want to publish a book, one of the most important things to consider is the cover—after all, we judge the book by the cover.&lt;/p&gt;
&lt;p&gt;And I did it the universally recommended way:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I hired a designer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Simple, right?&lt;/p&gt;
&lt;p&gt;But real talk; it’s not exactly that simple and I did a bunch of work to get a cover that I’m very happy with (scroll down if you just want to see the cover). This post is an attempt to gather the things I did, and I hope it’s helpful for you if you want to create a cover for your own book.&lt;/p&gt;
&lt;h1&gt;Preparations&lt;/h1&gt;
&lt;p&gt;Before contacting a designer I compiled a document with things that the designer might need. It contained these things, in as much detail and clarity as I could give:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Idea(s) for the cover&lt;/li&gt;
&lt;li&gt;The feeling I wanted the cover to invoke&lt;/li&gt;
&lt;li&gt;The art style&lt;/li&gt;
&lt;li&gt;Target audience&lt;/li&gt;
&lt;li&gt;Images used in the book&lt;/li&gt;
&lt;li&gt;Example of book covers in the genre&lt;/li&gt;
&lt;li&gt;Information on the book, such as print or ebook and the book dimensions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You might think this is overkill, but all the designers I contacted were deeply impressed by it, and I was told it was immensely helpful in producing the cover and saved us a lot of time.&lt;/p&gt;
&lt;p&gt;I had a pretty clear idea of what I wanted for the cover. It was a complex illustration, which is much more expensive than a simpler cover, but I liked the idea too much to throw it away. This is how I described it in the initial design document:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;While it should be clear that it’s a book about Bitcoin you should also be able to look at the cover and identify some of the topics I bring up in the book. Something that reveals more details and references the more you look at it.&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;My idea is to have a picture of a city street, with shops and signs on both sides. Something like this:&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/cover-help/city.jpg&quot; /&gt;
&lt;/figure&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;And in the middle should be a person with a mobile phone that shows an image with a Bitcoin logo. The person is confused and doesn’t know where to go and what the different things on the street are.&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;I like the cyberpunk aesthetic, but the cover should of course be less messy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And then a long list of ideas for what could be seen on the street. We scrapped most of them, even some of my favorites such as an S&amp;amp;M couple walking on the street, but they helped guide the process from beginning to end.&lt;/p&gt;
&lt;p&gt;The point of this exercise is to give the designer the tools to create a cover that matches what you want. The designer hasn’t read your book, so you must somehow transplant what’s in your head into theirs, and I think a design document like I created is a pretty good start.&lt;/p&gt;
&lt;h1&gt;Hiring a designer&lt;/h1&gt;
&lt;p&gt;I looked for designers in two places:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recommendations from reddit via &lt;a href=&quot;https://www.reddit.com/r/selfpublish/&quot;&gt;r/selfpublish&lt;/a&gt; (a subreddit focused on self-publishing)&lt;/li&gt;
&lt;li&gt;Contacted people who uploaded cool illustrations on reddit, and asked if they designed covers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I contacted a bunch of them, and ultimately chose &lt;a href=&quot;http://blark.com/&quot;&gt;Brad Lark&lt;/a&gt; for two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I liked his art-style (otherwise I wouldn’t even have bothered)&lt;/li&gt;
&lt;li&gt;He proposed an iterative process, where I paid in increments instead of a large clump sum&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The others I contacted wanted to be paid everything upfront, or half before we start and half when we finish. I’d be totally fine with that approach too, but they asked for $2,500 or $3,500 while Brad wanted an initial $350 and then we’d work from there. Avoiding the large initial investment was the decider for me. (The final cost landed at $1,754, which included the front, the spine, the back, typesetting and print setup.)&lt;/p&gt;
&lt;p&gt;Now you might wonder, is a cover really that expensive?&lt;/p&gt;
&lt;p&gt;No, you can get a standard cover much, much cheaper (and it might very well be the better financial decision for you).  But complex illustrations like the one I wanted are very time consuming, and thus, expensive.&lt;/p&gt;
&lt;h1&gt;Working with the designer&lt;/h1&gt;
&lt;p&gt;Don’t think that we’re done just because we’ve prepared an initial guiding document. Most of the effort was spent giving feedback and planning the next iteration, with +70 emails going back and forth until we arrived at the end result (&lt;em&gt;long&lt;/em&gt; emails, some as long as the initial design document itself!).&lt;/p&gt;
&lt;p&gt;Like with software development an &lt;a href=&quot;https://en.wikipedia.org/wiki/Iterative_and_incremental_development&quot;&gt;iterative and incremental process&lt;/a&gt; beats out a &lt;a href=&quot;https://en.wikipedia.org/wiki/Waterfall_model&quot;&gt;static waterfall-like process&lt;/a&gt; every time. It works by the designer providing a sketch (or several), and we give feedback and plan for the next iteration where the designer continues to improve until we arrive at something we’re happy with.&lt;/p&gt;
&lt;p&gt;(Incidentally writing a book is also an iterative process, but more on that in a later blog post.)&lt;/p&gt;
&lt;p&gt;I think an iterative process is so important, that if your designer doesn’t want to work this way, then you should find someone else.&lt;/p&gt;
&lt;p&gt;How to give feedback is an art in itself, here are some concrete things I focused on when receiving a sketch or a draft:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What did I like?&lt;/li&gt;
&lt;li&gt;What didn’t I like?&lt;/li&gt;
&lt;li&gt;What am I unsure about?&lt;/li&gt;
&lt;li&gt;And for the above, &lt;strong&gt;why&lt;/strong&gt; do I feel this way?&lt;/li&gt;
&lt;li&gt;Concrete next actions to take (one of the most important lessons I’ve learnt from the &lt;a href=&quot;https://hamberg.no/gtd&quot;&gt;Getting Things Done methodology&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example “I like the birds” isn’t as good as “I like the birds because they give a nice dystopian feeling”, which lead to us adding a bunch more details that strengthened the dystopian cyberpunk vibe.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/birds.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;But sometimes it’s very difficult. In the first drafts, I didn’t like the person in the middle. I couldn’t really explain why… Maybe it didn’t feel finished? But when pressed I had to settle with “I don’t know”.&lt;/p&gt;
&lt;p&gt;Don’t worry about hurting feelings or settling on something you’re not completely satisfied with; the designer should be a professional and as long as you’re respectful and your feedback is focused on concrete things, there shouldn’t be any issues.&lt;/p&gt;
&lt;h1&gt;Email communication&lt;/h1&gt;
&lt;p&gt;Because all our communication was over email, I wanted to dedicate some time to the art of writing effective emails (which with the prevalence of remote working might be one of the most important skills you can focus on).&lt;/p&gt;
&lt;p&gt;I have some simple rules I try to follow, and they’ve proved to be very effective:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The purpose of the email should be very clear&lt;/li&gt;
&lt;li&gt;It should be clear for any reader if the email is specifically targeting them&lt;/li&gt;
&lt;li&gt;It must be clear what actions needs to be taken, and by whom&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While the first two aren’t very relevant for this case, the third is very important. After the email, the designer should know what changes should be made and have received enough information to move in the right direction (but follow-up emails and clarifications should be expected).&lt;/p&gt;
&lt;p&gt;Concretely after receiving a new draft, I would write an email looking something like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Hey, some good progress here and I’ve left some feedback and a plan for the next iteration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I like&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I think the stance/posture of the person is good, and the confusion is very clear.&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What I’m unsure about&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I appreciate the “insert card” sign on the toilet, without it there wouldn’t be much point. But is it readable?&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What I dislike and what we should change&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Too much neon. I think I’d like more details on other elements that are more in the dark/grungy/depressing/dystopian style? Maybe like the sky or the street? The colored windows work well here, and so does the sidewalks.&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ideas for next iteration&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bank&lt;br /&gt;
In true cyberpunk fashion banks and megacorps are evil. I don’t know how to convey this well though?&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Concrete steps for next iteration&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Rework the “dislikes” mentioned above&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Neon (make it more gritty)&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add some street level shops&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, this kind of email can be very long, but it’s important not to be verbose. Write enough to get your point across, but not more. Sometimes a “I paid the invoice, could you please confirm?” is good enough.&lt;/p&gt;
&lt;h1&gt;From the first to the second iteration&lt;/h1&gt;
&lt;p&gt;While we did four iterations, the transformation from the first to the second was pretty impressive.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/firstpass.png&quot; /&gt;
&lt;figcaption&gt;The initial sketch&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My initial reaction to the initial sketch was… Not that good. I’m not sure what I was expecting, but it was something &lt;em&gt;more&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Still, I took a long hard look at found a number of things I did like, and a long list of things I wanted to change and add, and had a long email conversation of how to proceed. After what felt like a long wait (but in reality wasn’t) the next sketch felt completely different:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/secondpass.jpeg&quot; /&gt;
&lt;figcaption&gt;After extensive feedback and a number of brainstorm/planning back and forths&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Impressive!&lt;/p&gt;
&lt;p&gt;I guess the lesson here is that it’s fine to feel disappointed at first, but an iterative process and effective communication can do wonders.&lt;/p&gt;
&lt;h1&gt;The end result&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/cover-front-v1.png&quot; /&gt;
&lt;figcaption&gt;The final cover&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/cover-hand.png&quot; /&gt;
&lt;figcaption&gt;The cover looks great in real life too&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Overall, I’m super happy with the cover and I’ve gotten a ton of praise for it. I’m not sure if it was a wise financial decision to spend that much on a cover, as it’s likely I won’t sell enough books to cover the cost, but I can’t complain about the end result.&lt;/p&gt;
&lt;p&gt;Still, there are some things I would’ve done differently. We did a last round that included adding a title on the front, on the spine and text to the back of the book. But the text layout is something I could’ve done myself, especially as I’ve done some adjustments afterwards myself.&lt;/p&gt;
&lt;p&gt;The book itself? It’s called &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;Why Cryptocurrencies?&lt;/a&gt; and I plan to release it at the end of May. It’s also available to &lt;a href=&quot;https://whycryptocurrencies.com/toc.html&quot;&gt;read online for free&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><title>Getting the book into my hands</title><id>http://jonashietala.se/blog/2021/04/22/getting_the_book_into_my_hands/index.html</id><updated>2024-04-02T04:12:58+00:00</updated><link href="https://www.jonashietala.se/blog/2021/04/22/getting_the_book_into_my_hands" rel="alternate"/><published>2021-04-22T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Around a month ago I placed an order for a reference copy of my upcoming book &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;Why Cryptocurrencies?&lt;/a&gt;. I took the cheapest shipping option at IngramSpark, without tracking and, apparently, without customs declarations as it got stuck in customs for several weeks.&lt;/p&gt;
&lt;p&gt;But it’s here now!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/cover-hand.png&quot; /&gt;
&lt;figcaption&gt;It’s here! It’s real!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There’s something special of having worked on something for more than two years and finally getting the result in your hands. Somehow, it makes it all feel real.&lt;/p&gt;
&lt;p&gt;Also, while my parents, my girlfriend and her parents know that I’ve been writing a book, they were quite surprised and impressed when I showed it to them. I think that’s a good sign?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/cover-name.png&quot; /&gt;
&lt;figcaption&gt;Irrefutable proof that I made this book&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I was very worried that the images in the book would be blurry. They’re supposed to be at least 300 PPI, but I had accidentally made some of them in 72 PPI. The images are hand-drawn using a digital pen in &lt;a href=&quot;https://krita.org/en/&quot; title=&quot;Krita | Digital Painting&quot;&gt;Krita&lt;/a&gt;, so they weren’t vector based either, which in hindsight might have been a good idea. I tried to upscale the images, but on the computer some of them looked a little blurry, so I was sure I had to recreate them.&lt;/p&gt;
&lt;p&gt;But I didn’t have to worry, the images looks good. Some even looks great!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/bank.png&quot; /&gt;
&lt;figcaption&gt;My camera skills don’t do the images justice—they look very good in real life&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/cover-keyb.png&quot; /&gt;
&lt;figcaption&gt;Yes, flexing like this is the real reason I have a split keyboard&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One funny thing about IngramSpark is that colored books cost almost the same as black-and-white books. So we can get some sweet syntax highlighting as well:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/code.png&quot; /&gt;
&lt;figcaption&gt;It’s really annoying that publishers of many programming books only publish in black-and-white. It’s unfortunate that this is the &lt;em&gt;only&lt;/em&gt; example of syntax highlight in the entire book, but it does look great. My next book, if I ever write one, will be full of code examples so I can show traditional publishers how a programming book should look like.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So does this mean that the book will finally release?&lt;/p&gt;
&lt;p&gt;While I don’t have to rework the images, which would’ve been a large time sink, there are minor adjustments I need to do. I also need to re-read the book from cover to cover, to ensure that it looks as good as I can possibly make it.&lt;/p&gt;
&lt;p&gt;The plan was to release in April, but due to the shipping delays I don’t have time to make these changes, so I’ll have to postpone it into May.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;Pre-order or read the book here!&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>The Coinparty hackathon, take two</title><id>http://jonashietala.se/blog/2021/01/12/coinparty_2021/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2021/01/12/coinparty_2021" rel="alternate"/><published>2021-01-12T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;In December &lt;a href=&quot;/blog/2020/11/30/an_elixir_based_payment_processor_for_the_coinparty_2020_hackathon/&quot; title=&quot;An Elixir based payment processor for the Coinparty hackathon&quot;&gt;I declared&lt;/a&gt; that I would enter a &lt;a href=&quot;https://coinparty.org/&quot; title=&quot;Coinparty, a Bitcoin Cash hackathon&quot;&gt;Bitcoin Cash hackathon&lt;/a&gt; and I was excited to give my procrastination a kick in the balls. Unfortunately the hackathon was postponed to January just an hour later. Maybe the organizers didn’t think my project was exciting enough or something? Oh well.&lt;/p&gt;
&lt;p&gt;It’s January and I want to give it a try again! This time I got my friend to join me, but otherwise the project is the same. &lt;a href=&quot;/blog/2020/11/30/an_elixir_based_payment_processor_for_the_coinparty_2020_hackathon/&quot; title=&quot;An Elixir based payment processor for the Coinparty hackathon&quot;&gt;The article I wrote last time&lt;/a&gt; is still relevant, so you should go read that.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devpost.com/software/bitpal&quot; title=&quot;BitPal on DevPost&quot;&gt;Link to the devpost page&lt;/a&gt; where we’ll try to post some updates.&lt;/p&gt;
</content></entry><entry><title>2020 in review</title><id>http://jonashietala.se/blog/2021/01/04/2020_in_review/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2021/01/04/2020_in_review" rel="alternate"/><published>2021-01-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;And so 2020 has come to an end. On a global scale it’s been quite a horrible year, and for me personally it’s been both good and bad. Luckily we haven’t been directly affected by COVID too much, but it’s still been very disruptive. Either way as &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly reviews&quot;&gt;I’ve done for years now&lt;/a&gt; it always makes me feel better to do a little yearly review, as when I sit down in write it down I’ve always done more things than I first realize.&lt;/p&gt;
&lt;h1&gt;2020 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;We got another child.&lt;/p&gt;
&lt;p&gt;They’re both so wonderful and I wouldn’t trade them for anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read or listened to some books.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/44767458-dune&quot; title=&quot;Dune&quot;&gt;Dune&lt;/a&gt; and &lt;a href=&quot;https://www.goodreads.com/book/show/37976541-bad-blood&quot; title=&quot;Bad Blood&quot;&gt;Bad Blood&lt;/a&gt; are the ones I remember the most.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a bunch of light novels.&lt;/p&gt;
&lt;p&gt;There are many good ones, and to be honest I don’t remember all the ones I read. &lt;em&gt;Second Coming of Gluttony&lt;/em&gt; and &lt;em&gt;Returner’s Magic Should be Special&lt;/em&gt; are two of my all-time favorites.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Started a Grappling club.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2020 Geek Achievements&lt;/h1&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;“Finished” &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?: What they are, what they do and why they matter&quot;&gt;my book&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Although there’s a bunch of things left until I can truly call it complete, I’ve finished all the chapters at least.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some Rust.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some Racket. Used it to &lt;a href=&quot;/blog/2020/05/03/how_i_wrote_my_book_using_pollen/&quot; title=&quot;How I wrote my book using Pollen&quot;&gt;generate the online version of my book&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote a little Elixir.&lt;/p&gt;
&lt;p&gt;Mostly I read and worked through a bunch of Elixir books. &lt;a href=&quot;https://pragprog.com/titles/elixir16/programming-elixir-1-6/&quot; title=&quot;Programming Elixir&quot;&gt;Programming Elixir&lt;/a&gt;, &lt;a href=&quot;https://pragprog.com/titles/phoenix14/programming-phoenix-1-4/&quot; title=&quot;Programming Phoenix&quot;&gt;Programming Phoenix&lt;/a&gt;, &lt;a href=&quot;https://pragprog.com/titles/wmecto/programming-ecto/&quot; title=&quot;Programming Ecto&quot;&gt;Programming Ecto&lt;/a&gt; and &lt;a href=&quot;https://pragprog.com/titles/sbsockets/real-time-phoenix/&quot; title=&quot;Real-Time Phoenix&quot;&gt;Real-Time Phoenix&lt;/a&gt; was my summer reading and &lt;a href=&quot;https://www.manning.com/books/elixir-in-action&quot; title=&quot;Elixir in Action&quot;&gt;Elixir in Action&lt;/a&gt; has entertained me during the winter holidays.&lt;/p&gt;
&lt;p&gt;Even though I haven’t finished Elixir in Action yet, it’s probably my favorite and if you’re looking for a good Elixir resource I’d suggest you start with it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote a little C.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote a little Python.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Started working professionally in Rust.&lt;/p&gt;
&lt;p&gt;I’ve come into the mindset of personal development and steering my software development career to focus on technologies that I find interesting and think are really good is something I want to prioritize. Having a job that pays me to work on Rust fits perfectly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Built some custom keyboards: the &lt;a href=&quot;https://www.gboards.ca/product/gergoplex&quot; title=&quot;GergoPlex&quot;&gt;GergoPlex&lt;/a&gt; and the &lt;a href=&quot;https://splitkb.com/products/kyria-pcb-kit&quot; title=&quot;Kyria PCB Kit&quot;&gt;Kyria&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Got up to 40-50 wpm on an alternate keyboard layout.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/beakl-base.png&quot; /&gt;
&lt;figcaption&gt;Based on &lt;a href=&quot;https://deskthority.net/wiki/BEAKL#BEAKL_15&quot; title=&quot;BEAKL 15 keyboard layout&quot;&gt;BEAKL 15&lt;/a&gt;, with some modifications.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;However as I’m writing this I’ve moved on to yet another layout. The jury is still out on that one.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2020 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Did not finish &lt;a href=&quot;https://shop.jcoglan.com/building-git/&quot; title=&quot;Building Git&quot;&gt;building git&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I did go through the first part using Rust, but I ran out of steam just as it started to get really interesting with implementing branching and merging. I do need to get back to it some day.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Did not train grappling that much.&lt;/p&gt;
&lt;p&gt;COVID didn’t kill me or my family, but it as good as killed my biggest hobby.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Did not actually finish the book.&lt;/p&gt;
&lt;p&gt;It’s easy to blame COVID or getting another child, but the truth is as the project’s nearing completion I’ve been running out of steam. Writing a chapter was easy, but proof-reading it and polishing it is harder. Uploading a chapter online was easy, but formating it in InDesign is harder.&lt;/p&gt;
&lt;p&gt;Realistically there’s not that much left, but it still feels like walking in mud. Maybe that’s just how it feels with big projects like these? I’m certainly a starter, not a finisher.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Did not blog that much.&lt;/p&gt;
&lt;p&gt;I want to blog more and do more big articles, but that will have to wait until my book project is completely done. My writing energy isn’t enough to do them both.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2021&lt;/h1&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;Take the COVID vaccine.&lt;/li&gt;
&lt;li&gt;Grapple more.&lt;/li&gt;
&lt;li&gt;Finish the book project.&lt;/li&gt;
&lt;li&gt;Completely migrate to the new keyboard and the new layout.&lt;/li&gt;
&lt;li&gt;Read more books.&lt;/li&gt;
&lt;li&gt;Focus on personal development and/or another project.&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>An Elixir based payment processor for the Coinparty hackathon</title><id>http://jonashietala.se/blog/2020/11/30/an_elixir_based_payment_processor_for_the_coinparty_2020_hackathon/index.html</id><updated>2024-07-01T05:28:09+00:00</updated><link href="https://www.jonashietala.se/blog/2020/11/30/an_elixir_based_payment_processor_for_the_coinparty_2020_hackathon" rel="alternate"/><published>2020-11-30T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;
&lt;img src=&quot;/images/coinparty-full.svg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Bitcoin Unlimited is hosting &lt;a href=&quot;https://coinparty.org/&quot;&gt;a Bitcoin Cash hackathon this December&lt;/a&gt; and it seemed like a good opportunity for me to explore how to program against Bitcoin Cash, and it gives me an excuse to build something real with &lt;a href=&quot;https://www.phoenixframework.org/&quot;&gt;Phoenix&lt;/a&gt; and Elixir. (While an event like this might help combat my procrastination, I should really work on finishing my book, so this in itself is also procrastination.)&lt;/p&gt;
&lt;p&gt;Therefore I’d like to integrate BCH payments into a simple website made with the &lt;a href=&quot;https://www.phoenixframework.org/&quot;&gt;Phoenix Framework&lt;/a&gt;, with the possibility of extending it to a generalized cryptocurrency payment processor (if it’s sufficiently useful).&lt;/p&gt;
&lt;p&gt;I’m also doing it myself because after entertaining my two kids, my girlfriend and spending time at work there’s not that much time for the hackathon, so I figured it’s best if I focus on something small and do it in my own pace.&lt;/p&gt;
&lt;h1&gt;My use-case&lt;/h1&gt;
&lt;p&gt;Ever since I started working on &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;my book about cryptocurrencies&lt;/a&gt; I’ve been planning to sell the digital version on my site, payable with cryptocurrencies of course.&lt;/p&gt;
&lt;p&gt;To make it as accessible as possible I want to support different cryptocurrencies and sell it in a pay-what-you-want scheme (but more than 0). As you can send really small amounts of money this would allow people in poor countries to buy the e-book, people who otherwise would’ve been priced out.&lt;/p&gt;
&lt;p&gt;It would also act as a good introduction for people who have received small amounts of cryptocurrency tips. For instance it’s common on Reddit to tip &amp;lt; $1 of Bitcon Cash via &lt;a href=&quot;https://www.chaintip.org/&quot;&gt;chaintip&lt;/a&gt;, but it’s harder to find anything useful to do with that amount of money.&lt;/p&gt;
&lt;p&gt;When looking for a payment processor or a library to help me out, I have a few requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Easily integrated to a site made with the &lt;a href=&quot;https://www.phoenixframework.org/&quot;&gt;Phoenix Framework&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports multiple cryptocurrencies&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open-source&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Free&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No minimum payment limit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No KYC/AML&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Receive payments directly to my own crypto wallet(s)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I should be able to verify payments via full nodes on my own hardware&lt;/p&gt;
&lt;p&gt;If you handle higher value payments or have high privacy requirements this is a must, but for my simple use-case I don’t really have to. I just &lt;em&gt;want to&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;I couldn’t find an existing solution that fits all my needs&lt;/h1&gt;
&lt;p&gt;Turns out this is surprisingly hard. While it’s possible my DuckDuckGo and Google skills have failed me, I couldn’t find anything that fit my needs and they all require me to compromise on something. For instance:&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://bitpay.com/&quot;&gt;BitPay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If I was a normal merchant I might prefer to get my payments in fiat, but it doesn’t work with my requirements at all.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://paybutton.org/&quot;&gt;PayButton&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Makes it very easy to accept Bitcoin Cash. Just add a few lines of JavaScript and you’re done. But it doesn’t allow you to run your own node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/gcash/bchwallet&quot;&gt;bchwallet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Does nearly everything technical I want to support, I’d just have to integrate it into my site in some way. Unfortunately it only supports Bitcoin Cash.&lt;/p&gt;
&lt;p&gt;(I might use this under the hood, but I haven’t done enough research to know if I need to or if I can just interface with a node directly.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://btcpayserver.org/&quot;&gt;BTCPayServer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Many say this is the gold standard of accepting cryptocurrency payments. It does everything I want (and more!). Writing a custom integration shouldn’t be too hard either.&lt;/p&gt;
&lt;p&gt;Although “BTC” in the name might lead you to believe that it only supports Bitcoin, it does support a number of other cryptocurrencies, such as Litecoin, Monero and even Bitcoin Gold…&lt;/p&gt;
&lt;p&gt;But it doesn’t support Bitcoin Cash.&lt;/p&gt;
&lt;p&gt;Why?  It seems the maintainer has &lt;a href=&quot;https://mobile.twitter.com/BtcpayServer/status/963686582862655488&quot;&gt;bought into the “BCash” propaganda&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I have my response. no support for it. And I will not accept PRs until all BCash wallets stop considering Bitcoin addresses as valid. (Not an help desk) Then finally I will accept PRs on the condition that the name “Bitcoin Cash” never appear. (BCH or BCash only)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note the double standard of supporting Bitcoin Gold and Bitcoin Plus even though they both consider Bitcoin addresses as valid and they both have “Bitcoin” in their name, which is also used &lt;a href=&quot;https://docs.btcpayserver.org/Altcoins/&quot;&gt;in their documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And then there’s professional comments like these:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/btcpayserver-bcash.png&quot; /&gt;
&lt;figcaption&gt;&lt;a href=&quot;https://mobile.twitter.com/BtcpayServer/status/1031388746531332096&quot;&gt;The market has spoken!&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Sigh.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cryptowoo.com/&quot;&gt;CryptoWoo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a nice plugin that supports a variety of different cryptocurrencies, and it would fit except it’s not open-source, it’s not free as I want to support XMR and it only works in WooCommerce.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://nowpayments.io/&quot;&gt;NOWPayments&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Easy integration and supports lots of coins, but they have a minimum payment amount of $3-5, they have KYC/AML and I can’t use my own nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Why is this important?&lt;/h1&gt;
&lt;p&gt;Now my little use-case isn’t important in the grand scheme of things, but at the same time it is. So let’s take a step back for a sec to see why.&lt;/p&gt;
&lt;p&gt;People are currently gushing over Bitcoin’s price again and are asking the question &lt;em&gt;when will cryptocuriencies win?&lt;/em&gt; At $50,000 per coin? At $100,000? Or perhaps at *gasp* $1 million?&lt;/p&gt;
&lt;p&gt;I think this misses the mark, and it’s not ambitious enough.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The end goal isn’t a fiat price, it’s not having to care about the fiat price.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I want to be able to receive my salary, pay my bills and buy the stuff I need using crypto, without having to go back to fiat. In short I think cryptocurrencies win when they’re as widely accepted as PayPal or VISA.&lt;/p&gt;
&lt;p&gt;And to get there we need as many merchants as possible to accept crypto. Which means it must be as easy as possible to accept them for your business; regardless if it’s in-person or online, what tech is used to build your website or whatever requirements you might have.&lt;/p&gt;
&lt;p&gt;That’s why it’s so important to remove friction of any kind from the process of accepting payments. And that’s why even my little project is important.&lt;/p&gt;
&lt;h1&gt;A simple plan for the hackathon&lt;/h1&gt;
&lt;p&gt;Given that I don’t have a lot of time, and I haven’t programmed against cryptocurrencies before and I’ll also use a language and framework I have little experience with, it makes sense to have a modest goal.&lt;/p&gt;
&lt;p&gt;My goal is simply to accept BCH payments in a small demo website, and verify them using my own full node.&lt;/p&gt;
&lt;h1&gt;Growing to a fully fledged project&lt;/h1&gt;
&lt;p&gt;If it makes sense to do so I might develop the project further after the hackathon, and I do have a tentative plan on how to do that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Refactor it out into an Elixir library&lt;/p&gt;
&lt;p&gt;To make it easy to include it into a new Elixir/Phoenix website. It would be great if I could do this during the hackathon as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;REST API&lt;/p&gt;
&lt;p&gt;On top of the library we can build a REST API so that we can integrate payments into other frameworks or e-commerce stores that don’t use Elixir.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Documentation&lt;/p&gt;
&lt;p&gt;A boring—but very important—part of any API or service is documentation. People think that features is what differentiates the good from the bad, but frequently I find quality documentation is the decider.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More integrations&lt;/p&gt;
&lt;p&gt;I’ll start with an integration for Phoenix, because that’s what I prefer. But there are tons of general frameworks such as Ruby on Rails, Django and Laravel, or e-commerce stores like OpenCart and WooCommerce. The goal must be to support the popular ones to make it as easy as possible to start accepting payments.&lt;/p&gt;
&lt;p&gt;And it should be easy to write your own custom integration if native support is missing or include a small JavaScript snippet à la PayButton or Stripe.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Self-hosted and public servers&lt;/p&gt;
&lt;p&gt;It should be easy to spin up a server of your own, so you have full control of the payment processing. But everyone don’t want or need to do this, and for them we should have public servers they can connect to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support more cryptocurrencies&lt;/p&gt;
&lt;p&gt;This is important as merchants would otherwise be forced to integrate multiple payment processors for the different cryptocurrencies they’d like to support. This is very cumbersome and they might instead opt to use BTCPayServer—that lacks Bitcoin Cash—or skip cryptocurrency support entirely.&lt;/p&gt;
&lt;p&gt;The fight for adoption isn’t a zero-sum game between competing cryptocurrencies—it’s a fight to convince the rest of the world that they should start using cryptocurrencies.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Under these larger goals there are many details missing. Enhancing 0-conf security using double-spend proofs is one example, supporting different payment protocols is another.&lt;/p&gt;
&lt;p&gt;While this project could grow massively in size, I will start small and expand if it’s valuable to do so. But the plan for the future is here.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Shoot for the moon. Even if you miss, you’ll land among the stars.&lt;/p&gt;
&lt;p&gt;— Norman Vincent Peale&lt;/p&gt;
&lt;/blockquote&gt;</content></entry><entry><title>An update on my book &apos;Why Cryptocurrencies?&apos;</title><id>http://jonashietala.se/blog/2020/10/09/an_update_on_my_book_why_cryptocurrencies/index.html</id><updated>2024-04-02T04:12:58+00:00</updated><link href="https://www.jonashietala.se/blog/2020/10/09/an_update_on_my_book_why_cryptocurrencies" rel="alternate"/><published>2020-10-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Five months ago I &lt;a href=&quot;https://www.jonashietala.se/blog/2020/04/29/my_book_why_cryptocurrencies_is_done/&quot; title=&quot;My book is done!&quot;&gt;gloriously declared that “my book was done”&lt;/a&gt;. Since then I’ve been working hard to finish the book.&lt;/p&gt;
&lt;p&gt;Sorry that’s a bit of a lie, I’ve had a nice long vacation where I didn’t work on the book and I’m also on part-time parental leave. And believe me there’s not a lot of time left over with two kids pulling for your attention.&lt;/p&gt;
&lt;p&gt;Although they won’t be finished this year, I’ve made some good progress on the e-book and on formating the physical book and the goal is to have them ready some time next year. The plan is to release the e-book (PDF and epub) as pay-what-you-want for cryptocurrencies on my site while releasing it as normal on Amazon and similar.&lt;/p&gt;
&lt;p&gt;I’ve also done a re-read of the book to make a bunch of fixes, so if you haven’t read the book yet now might be a good time. It’s &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;completely free to read online&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Because I started the book almost two years ago (yikes!) there are some new events that I’ve added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As a response to COVID-19, &lt;a href=&quot;https://whycryptocurrencies.com/a_defective_system.html#the-stock-market-magic-trick&quot; title=&quot;The stock market magic trick&quot;&gt;the FED has printed an extreme amount of money in a very short time&lt;/a&gt;, displaying the problem with unsound money for all to see.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nationalreview.com/2020/07/life-in-lebanon-under-hyperinflation/&quot; title=&quot;Life in Lebanon under Hyperinflation&quot;&gt;Lebanon became to second country to experience hyperinflation in 2020&lt;/a&gt; (Venezuela didn’t escape theirs).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reuters.com/article/us-usa-nsa-spying-idUSKBN25T3CK&quot; title=&quot;U.S. court: Mass surveillance program exposed by Snowden was illegal&quot;&gt;The U.S. court declared that the mass surveillance program exposed by Snowden was illegal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The extradition hearing against Assange, where the U.K. will decide if they should deport him to the U.S., &lt;a href=&quot;https://www.craigmurray.org.uk/archives/2020/10/your-man-in-the-public-gallery-assange-hearing-day-21/&quot; title=&quot;Your Man in the Public Gallery: Assange Hearing Day 21&quot;&gt;is a complete farce&lt;/a&gt;. For example the U.S. managed to convince the judge that any reference to the torture in Guantánamo couldn’t be mentioned, so key witnesses were blocked from testifying and evidence were censored.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yet I feel that nothing has really changed. The argument for cryptocurrencies are the same as two years ago, and they’re only growing stronger.&lt;/p&gt;
</content></entry><entry><title>ghc 8.8.3 cannot find cabal 3.0.0.0 packages</title><id>http://jonashietala.se/blog/2020/05/09/ghc_cannot_find_cabal_packages/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2020/05/09/ghc_cannot_find_cabal_packages" rel="alternate"/><published>2020-05-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been using cabal to manage my Haskell dependencies for years, but when I last updated my system it suddenly stopped working. I installed my dependencies with &lt;code&gt;cabal install xmonad&lt;/code&gt;, and checked that it’s installed under &lt;code&gt;~/.cabal&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ ls .cabal/bin/
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;xmonad@
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But still when I go to compile my xmonad config file ghc says it cannot find it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Could not find module ‘XMonad’
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And indeed when I run &lt;code&gt;ghc-pkg list&lt;/code&gt; it does not list xmonad. That’s weird.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ cabal --version
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;cabal-install version 3.0.0.0
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ ghc --version
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;The Glorious Glasgow Haskell Compilation System, version 8.8.3
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Apparently this is &lt;a href=&quot;https://github.com/haskell/cabal/issues/6262&quot;&gt;a known issue&lt;/a&gt; (including the “blame game” if it’s a cabal or a ghc issue, but that doesn’t make it any less annoying for us who just want it work). The &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/17341&quot;&gt;ghc issue&lt;/a&gt; is still open.&lt;/p&gt;
&lt;p&gt;Fortunately there’s a solution.&lt;/p&gt;
&lt;p&gt;We can manually specify a package db for ghc-pkg so it’ll find our cabal modules:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ ghc-pkg --package-db ~/.cabal/store/ghc-8.8.3/package.db list
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;xmonad-0.15
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;xmonad-contrib-0.16
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And to make it permanent we can symlink the &lt;code&gt;package.db&lt;/code&gt; file as a ghc config:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ mkdir -p ~/.ghc/x86_64-linux-8.8.3/
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;$ ln -s ~/.cabal/store/ghc-8.8.3/package.db ~/.ghc/x86_64-linux-8.8.3/package.conf.d
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The name of the folder &lt;code&gt;x86_64-linux-8.8.3&lt;/code&gt; may differ, this one worked for me.&lt;/p&gt;
&lt;p&gt;And now &lt;code&gt;ghc-pkg list&lt;/code&gt; should find xmonad and compiling with ghc should find our missing cabal modules.&lt;/p&gt;
</content></entry><entry><title>How I wrote a book using Pollen</title><id>http://jonashietala.se/blog/2020/05/03/how_i_wrote_my_book_using_pollen/index.html</id><updated>2026-04-27T10:16:37+00:00</updated><link href="https://www.jonashietala.se/blog/2020/05/03/how_i_wrote_my_book_using_pollen" rel="alternate"/><published>2020-05-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I wrote &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;an online book&lt;/a&gt; using &lt;a href=&quot;https://docs.racket-lang.org/pollen/&quot; title=&quot;Pollen: the book is a program&quot;&gt;Pollen&lt;/a&gt;, a static site generator in &lt;a href=&quot;https://racket-lang.org/&quot; title=&quot;Racket&quot;&gt;Racket&lt;/a&gt;. &lt;a href=&quot;/blog/2019/03/03/first_impressions_of_pollen/&quot; title=&quot;First impressions of Pollen&quot;&gt;An earlier post&lt;/a&gt; contains my first impressions of it, but as the book is now completed I think I can summarize some implementation details in more detail with this post.&lt;/p&gt;
&lt;p&gt;I &lt;strong&gt;really&lt;/strong&gt; like the markup language and the usage of X-expressions. You do need to write code yourself for a bunch of things, but if you want a more complex markup for your site it’s a trade-off I’d make every time.&lt;/p&gt;
&lt;p&gt;If you want to use Pollen yourself the &lt;a href=&quot;https://docs.racket-lang.org/pollen/&quot; title=&quot;Pollen: the book is a program&quot;&gt;Pollen documentation&lt;/a&gt; is pretty good and you can also view the &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies&quot; title=&quot;Source code to the book &apos;Why Cryptocurrencies?&apos;&quot;&gt;source code of my book&lt;/a&gt; if you want more details on anything.&lt;/p&gt;
&lt;section id=&quot;Configuring-vim&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Configuring-vim&quot; class=&quot;heading-ref&quot;&gt;Configuring vim&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First off I do my writing and coding in vim (or rather &lt;a href=&quot;https://neovim.io/&quot; title=&quot;neovim&quot;&gt;neovim&lt;/a&gt;). I use plugins for Racket and Pollen (but truthfully I don’t remember what they do, syntax highlighting perhaps?) and I also have two keybindings for two special chars I don’t normally use:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;vimscript&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight vim&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line quotes viml&quot;&gt;&amp;quot; Plugin handling using vim-plug
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;Plug &lt;span class=&quot;string quoted single viml&quot;&gt;&amp;#39;https://github.com/wlangstroth/vim-racket&amp;#39;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Plug &lt;span class=&quot;string quoted single viml&quot;&gt;&amp;#39;https://github.com/otherjoel/vim-pollen.git&amp;#39;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line quotes viml&quot;&gt;&amp;quot; Easy insertion of special chars
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;support function viml&quot;&gt;imap&lt;/span&gt; &lt;span class=&quot;support type viml&quot;&gt;&amp;lt;C-L&amp;gt;&lt;/span&gt; λ
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support function viml&quot;&gt;imap&lt;/span&gt; &lt;span class=&quot;support type viml&quot;&gt;&amp;lt;C-E&amp;gt;&lt;/span&gt; ◊
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pollen markup uses &lt;code&gt;◊&lt;/code&gt; extensively so having an easy way to insert it is very important. And in Racket instead of writing lambdas 
&lt;code class=&quot;highlight racket&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ...&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; you can write 
&lt;code class=&quot;highlight racket&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ...&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;. It’s not necessary but I thought, why not?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Configuring-Pollen&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Configuring-Pollen&quot; class=&quot;heading-ref&quot;&gt;Configuring Pollen&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.racket-lang.org/pollen/&quot; title=&quot;Pollen: the book is a program&quot;&gt;Pollen documentation&lt;/a&gt; does a decent job of walking you through initial setup, there’s just a few gotchas I ran into.&lt;/p&gt;
&lt;p&gt;I wanted to turn three dots into a single character “…” and also remove &lt;code&gt;/index.html&lt;/code&gt; from links, while doing the default paragraph expansion and converting quotes and dashes to their special chars as described in the Pollen docs. I ended up with these decoding functions:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;ellipses&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;string-replace&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;...&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;…&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;de-indexify&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;string-replace&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;/index.html&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;string-proc&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;compose1&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;smart-quotes&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                              &lt;span class=&quot;variable other pollen&quot;&gt;smart-dashes&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                              &lt;span class=&quot;variable other pollen&quot;&gt;ellipses&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                              &lt;span class=&quot;variable other pollen&quot;&gt;de-indexify&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;std-decode&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;decode-elements&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                   &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:txexpr-elements-proc&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;decode-paragraphs&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                   &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:string-proc&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;string-proc&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                   &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:exclude-tags&lt;/span&gt; &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;figure&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The paragraph expansion is sometimes messed up, but I customized it by ignoring &lt;code&gt;figure&lt;/code&gt; and &lt;code&gt;pre&lt;/code&gt; while marking some tags as blocks:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;block-tags&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;append&lt;/span&gt; &amp;#39;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;tbody&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;dt&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;dl&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;default-block-tags&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This isn’t perfect, and for example when creating image figures I had to call &lt;code&gt;std-decode&lt;/code&gt; to parse caption text correctly.&lt;/p&gt;
&lt;p&gt;After a while I also wanted to organize my Racket files into a subfolder, and to get Pollen to recognize this I had to tell it to add them to the watchlist to have them reload the code automatically:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;racket&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic pollen&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;base&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;keyword operator arithmetic pollen&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;rkt-files&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;glob&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;rkt/*.rkt&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;cache-watchlist&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;rkt-files&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;The-markup-language&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-markup-language&quot; class=&quot;heading-ref&quot;&gt;The markup language&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pollen’s markup language can at first look extremely cumbersome, but I ended up liking it. Just prefix with &lt;code&gt;◊&lt;/code&gt; and you’ll automatically create html elements:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;First item&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;Second item&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;Third item&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also specify attributes such as classes, which is quite handy:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable named-arg pollen&quot;&gt;#:class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;my-class&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But the real power of the markup language is how easy it is to create your own tags. Just define regular Racket functions and provide them in pollen.rkt like so: 
&lt;code class=&quot;highlight racket&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;provide&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;all-from-out&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;rkt/tags.rkt&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Here are some examples of tags I’ve implemented:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Code&lt;/p&gt;
&lt;p&gt;Non-highlighted code is simple and is provided by:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;code&lt;/span&gt; . &lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;pre&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;code&lt;/span&gt; ,@&lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But for a more interesting example say that you want to include an external file and highlight it like so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta parens pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;code-hl&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;python3&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;scripts/gambling.py&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I implemented this by by calling out to &lt;code&gt;pygmentize&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;code-hl&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;lang&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;string-append&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;pygmentize -f html&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt; -l &lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;lang&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;string-&amp;gt;xexpr&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;with-output-to-string&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is an implementation in Pollen that does something similar, but it’s &lt;strong&gt;much&lt;/strong&gt; more complex. The simple one has worse performance, but since I only have a single instance where I highlight code it’s good enough for me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Quotes&lt;/p&gt;
&lt;p&gt;I use quotes heavily throughout the text, either as a standalone or wrapped in an epigraph (just used to italize quotes that begins a chapter):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;epigraph&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;qt&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable named-arg pollen&quot;&gt;#:author&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;Attributed to Michael Cassius McDonald&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    There&amp;#39;s a sucker born every minute
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Producing:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;epigraph&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;There’s a sucker born every minute&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Attributed to Michael Cassius McDonald&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s a large list of arguments to customize the quote, but that’s a little overkill to go through here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Links&lt;/p&gt;
&lt;p&gt;At first I used a very simple tag for links:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;In the text &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;link&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;my-link&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;link text&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta parens pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;my-link&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;https://some-url&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Later on I started separating links into regular links, book references and internal chapter references. This so I could mark when I had accessed external links, format book references in different ways and to generate alt-text for existing chapters easily. In practice link definitions looks like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;constant numeric pollen&quot;&gt;1984&lt;/span&gt;-&lt;span class=&quot;variable other pollen&quot;&gt;book&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;book-ref&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;https://www.goodreads.com/book/show/40961427-1984&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;George Orwell&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;1984&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;public-key-cryptography&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;ch-ref&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &amp;#39;&lt;span class=&quot;variable other pollen&quot;&gt;cryptography&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:ref&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;public-key-cryptography&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;Public-key cryptography&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;block-0&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;x-ref&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;2019-10-25&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;https://blockchair.com/bitcoin/block/0&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;Bitcoin block 0&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And used like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;book-qt&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric pollen&quot;&gt;1984&lt;/span&gt;-&lt;span class=&quot;variable other pollen&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt; ... &lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;em&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;Thoughtcrime&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;, as explored in the book &lt;span class=&quot;meta parens pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;book-link&lt;/span&gt; &lt;span class=&quot;constant numeric pollen&quot;&gt;1984&lt;/span&gt;-&lt;span class=&quot;variable other pollen&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;, ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;It uses &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;def&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;public-key-cryptography&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;public-key cryptography&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt; which allows ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;For example Satoshi &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;link&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;block-0&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;left a message&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt; in the first ever Bitcoin block:
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I could have gone much further with more link handling options, but I only really started branching out after I had written most of the book and going back to fix it is too much effort for no gain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;Sidenotes&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Sidenotes&quot; class=&quot;heading-ref&quot;&gt;Sidenotes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wrote a post about &lt;a href=&quot;/blog/2019/03/04/pollen_sidenotes/&quot; title=&quot;Tufte style sidenotes and marginnotes in Pollen&quot;&gt;Tufte style sidenotes and marginnotes in Pollen&lt;/a&gt; in an earlier post, but I’ve since then changed them from being hidden on smaller screens until you click them, to placed beneath the text instead of to the side.&lt;/p&gt;
&lt;hr&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whycrypto/sidenotes_wide.png&quot;&gt;
&lt;figcaption&gt;On a wider screen sidenotes are placed to the right.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whycrypto/sidenotes_below.png&quot;&gt;
&lt;figcaption&gt;If the sidenote doesn’t fit, it’s instead placed below.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;p&gt;Now it would be fairly easy (or at least it’s possible to style it in such a way with a lot of trial and error) to just move it to the right if it doesn’t fit. But notice that on the narrower screen the sidenote is placed below the last paragraph!&lt;/p&gt;
&lt;p&gt;I wanted to be able to customize the placement on the narrower screen as I wanted, while the floating sidenote should be as close to their reference as possible. I solved it, but it’s not very pretty…&lt;/p&gt;
&lt;p&gt;My first thought was to insert two sidenotes, and set 
&lt;code class=&quot;highlight css&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;display&lt;span class=&quot;entity other pseudo-class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;:&lt;/span&gt;none&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; to hide one of them. But this would break screen readers or simplified readers that removes much of the styling, such as the “reader view” in Firefox. So I opted for a more complex solution of manually modifying the top margin for each sidenote.&lt;/p&gt;
&lt;p&gt;In practice it means I insert a sidenote using 
&lt;code class=&quot;highlight pollen&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;sn&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;my-ref&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;, which by default inserts it below the current paragraph. If I want to manually place it somewhere else I use 
&lt;code class=&quot;highlight pollen&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;note-pos&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable named-arg pollen&quot;&gt;#:top&lt;/span&gt; -&lt;span class=&quot;constant numeric pollen&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;my-ref&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;. So for example:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;First paragraph.&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;sn&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;my-ref&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Second paragraph.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;note-pos&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable named-arg pollen&quot;&gt;#:top&lt;/span&gt; -&lt;span class=&quot;constant numeric pollen&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;my-ref&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The text for the sidenote is given by 
&lt;code class=&quot;highlight pollen&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;ndef&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;my-ref&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;Sidenote text here&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;, which can be paced anywhere in the source file.&lt;/p&gt;
&lt;p&gt;There’s a bunch of sidenote specific styling, but the important parts are given by:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;scss&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight scss&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;side-space&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment begin css&quot;&gt;/*&lt;/span&gt; Serves to take up space. Inline content from the chapter is floated on top. &lt;span class=&quot;punctuation definition comment end css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;420&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta at-rule media css&quot;&gt;&lt;span class=&quot;keyword control directive css&quot;&gt;&lt;span class=&quot;punctuation definition keyword css&quot;&gt;@&lt;/span&gt;media&lt;/span&gt; &lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type property-name css&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;variable other sass&quot;&gt;&lt;span class=&quot;punctuation definition variable sass&quot;&gt;$&lt;/span&gt;sidenote-float-width&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic sass&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;    &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sidenote&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta number float decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;1&lt;span class=&quot;punctuation separator decimal css&quot;&gt;.&lt;/span&gt;4&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword other important css&quot;&gt;!important&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta at-rule media css&quot;&gt;&lt;span class=&quot;keyword control directive css&quot;&gt;&lt;span class=&quot;punctuation definition keyword css&quot;&gt;@&lt;/span&gt;media&lt;/span&gt; &lt;span class=&quot;meta group css&quot;&gt;&lt;span class=&quot;punctuation section group begin css&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support type property-name css&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;variable other sass&quot;&gt;&lt;span class=&quot;punctuation definition variable sass&quot;&gt;$&lt;/span&gt;sidenote-float-width&lt;/span&gt;&lt;span class=&quot;punctuation section group end css&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;    &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;side-space&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    .sidenote &lt;span class=&quot;meta block css&quot;&gt;&lt;span class=&quot;punctuation section block begin css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;float&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;right&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;clear&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;right&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment begin css&quot;&gt;/*&lt;/span&gt; Approximate adjustment for notes at the last line of a paragraph. &lt;span class=&quot;punctuation definition comment end css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment begin css&quot;&gt;/*&lt;/span&gt; Will get overridden by local styles. &lt;span class=&quot;punctuation definition comment end css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-bottom&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-right&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;keyword operator arithmetic css&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;420&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;meta number integer decimal css&quot;&gt;&lt;span class=&quot;constant numeric value css&quot;&gt;380&lt;/span&gt;&lt;span class=&quot;constant numeric suffix css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;display&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;span class=&quot;support constant property-value css&quot;&gt;inline-block&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section block end css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And margins are overridden by 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;sidenote&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value style html&quot;&gt;&lt;span class=&quot;entity other attribute-name style html&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value style html&quot;&gt;&lt;span class=&quot;string quoted double&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value style html&quot;&gt;&lt;span class=&quot;source css&quot;&gt;&lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;margin-top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;-9&lt;span class=&quot;keyword other unit css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value style html&quot;&gt;&lt;span class=&quot;string quoted double&quot;&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The actual implementation of 
&lt;code class=&quot;highlight pollen&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;sn&lt;/span&gt;&lt;/code&gt; and 
&lt;code class=&quot;highlight pollen&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;ndef&lt;/span&gt;&lt;/code&gt; has grown surprisingly large and I went through the old version in the &lt;a href=&quot;/blog/2019/03/04/pollen_sidenotes/&quot; title=&quot;Tufte style sidenotes and marginnotes in Pollen&quot;&gt;previous post&lt;/a&gt;, so I’ll skip it here. The implementation has changed a little but not in any major way. You can always find the &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies/src/branch/master/rkt/sidenotes.rkt&quot; title=&quot;Codeberg sidenotes&quot;&gt;latest code on Codeberg&lt;/a&gt; if you’re interested.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Local-markup&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Local-markup&quot; class=&quot;heading-ref&quot;&gt;Local markup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another very powerful feature is that you can easily create custom markup for individual pages. For example in the chapter &lt;a href=&quot;https://whycryptocurrencies.com/what_is_money.html&quot; title=&quot;What is money?&quot;&gt;What is money?&lt;/a&gt; when giving a number of examples of money I wanted to add custom styling, like this:&lt;/p&gt;
&lt;hr&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whycrypto/ex_money_slim.png&quot;&gt;
&lt;figcaption&gt;I wanted to have an image associated with each example, alternated from left to right. I also wanted to give each example a title with an associated timeframe.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;p&gt;This is the tag I came up with:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta parens pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;money&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:img&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:date&lt;/span&gt; [&lt;span class=&quot;variable other pollen&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;constant character lisp&quot;&gt;#f&lt;/span&gt;] . &lt;span class=&quot;variable other pollen&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;xdate&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;cond&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       [&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator logical pollen&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;list?&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;null?&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;date&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,@&lt;span class=&quot;variable other pollen&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       [&lt;span class=&quot;variable other pollen&quot;&gt;date&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;date&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       [&lt;span class=&quot;keyword control pollen&quot;&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;example&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;src&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;txt&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;header&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;h3&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          ,&lt;span class=&quot;variable other pollen&quot;&gt;xdate&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ,@&lt;span class=&quot;variable other pollen&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which can be called like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;money&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;Dogecoin&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:date&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;2013&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:img&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;images/doge.png&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Dogecoin is a cryptocurrency, while created as a &amp;quot;joke currency&amp;quot;, it quickly gained popularity as a tipping tool online. You can still find merchants who accept it today for things like domain names, web hosting, VPNs or games.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To produce this html:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;images/doge.png&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;txt&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Dogecoin&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;2013&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Dogecoin is a cryptocurrency, while created as a “joke currency”, it quickly gained popularity as a tipping tool online. You can still find merchants who accept it today for things like domain names, web hosting, VPNs or games.&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So easy! So powerful! So great!&lt;/p&gt;
&lt;p&gt;Of course you could’ve done this manually in for example Markdown, but with 10 different examples that’s a ton of copy-pasting making any changes to the html &lt;strong&gt;really&lt;/strong&gt; annoying to make. I could’ve also written a callback in for example Hakyll (the site generator I use for this blog) that I could then call from my markup file, but having the code embeddable right next to the markup is much nicer and more performant.&lt;/p&gt;
&lt;p&gt;I use local custom markup all over the place, another example is styling transcripts of a Youtube video:&lt;/p&gt;
&lt;hr&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/whycrypto/transcript.png&quot;&gt;
&lt;figcaption&gt;The timestamps should be aligned in a certain way and have a horizontal bar.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;p&gt;We could be as explicit as we were with the money example, but here I wanted it to be simpler and to auto detect the timestamps. So I can write it like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable named-arg pollen&quot;&gt;#:class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;transcript-wrapper&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;transcript&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      02:34  He&amp;#39;s got an RPG [Rocket Propelled Grenade]?
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      02:35  All right, we got a guy with an RPG.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Except now we know it&amp;#39;s not an RPG but a camera held by a Reuters journalist.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;transcript&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      03:45  All right, hahaha, I hit [shot] &amp;#39;em...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      04:55  Oh, yeah, look at those dead bastards.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      05:00  Nice.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      06:57  Come on, buddy.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      07:01  All you gotta do is pick up a weapon.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  After killing a bunch of people they&amp;#39;re looking at an injured person crawling on the ground wanting him to pick up a weapon---so they&amp;#39;re allowed to kill him.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This can be accomplished by writing a bit of lisp code in the tag that splits the strings on the double spaces:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta parens pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;transcript&lt;/span&gt; . &lt;span class=&quot;variable other pollen&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;make-row&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;string=?&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant character escape lisp&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;cols&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;string-split&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;  &lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;row&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;time&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;car&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;txt&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,@&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;cdr&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;transcript&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      ,@&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;make-row&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(Yes I know that the “…” row will generate a 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;...&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; and a 
&lt;code class=&quot;highlight html&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;txt&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; element, but it doesn’t affect the appearance.)&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Table-of-contents&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Table-of-contents&quot; class=&quot;heading-ref&quot;&gt;Table of contents&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pollen have automatic support for tracking table of contents, called a pagetree. It’s not something I use for two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
I wanted to be able to display chapters not written yet
&lt;/li&gt;
&lt;li&gt;
I wanted a second layer in the chapter hierarchy
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So it could look like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;toc&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; This replaces the previously hand-made pagetree in index.ptree.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; String entries gets removed and are treated as planned chapters.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;eli5&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;about_the_book&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;variable other pollen&quot;&gt;acknowledgements&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;variable other pollen&quot;&gt;how_to_use&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;Completely free&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;About me, the author&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;what_is_a_cryptocurrency&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;variable other pollen&quot;&gt;properties_of_a_cryptocurrency&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;variable other pollen&quot;&gt;how_do_cryptocurrencies_work&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where I have a main section with a number of chapters inside and denote an unfinished chapter with the planned title. The functions that transforms this into output is also custom, &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies&quot; title=&quot;Source code to the book &apos;Why Cryptocurrencies?&apos;&quot;&gt;see the source&lt;/a&gt; if you’re curious.&lt;/p&gt;
&lt;p&gt;One annoyance I have is that titles of chapters are also defined with Racket code:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta parens pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define-meta&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;For the unbanked&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means I cannot automatically fetch the chapter title (for a better alt-text when linking to chapters) because it might cause a circular dependency as it has to load the whole chapter!&lt;/p&gt;
&lt;p&gt;My extremely ugly workaround was to define links and their alt-text manually:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;for_the_unbanked&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;ch-ref&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &amp;#39;&lt;span class=&quot;variable other pollen&quot;&gt;for_the_unbanked&lt;/span&gt;.&lt;span class=&quot;variable other pollen&quot;&gt;html&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;For the unbanked&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yes this means I’ll duplicate the post title, but I added chapter alt-text after the book was already done, so I didn’t bother doing it a better way.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Hosting&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Hosting&quot; class=&quot;heading-ref&quot;&gt;Hosting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve hosted my blog as a static webpage on Amazon S3 for years. It has worked well so being lazy I did the same with the book. I’ve described how to easily set it up with SSL &lt;a href=&quot;/blog/2019/04/03/easy-setup-of-a-static-site-on-amazon-s3-with-ssl/&quot; title=&quot;Hosting a static site on Amazon S3&quot;&gt;in an earlier post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To update the site I use an old Perl script that shells out to &lt;code&gt;s3cmd&lt;/code&gt; to upload data. It will generate commands like:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;s3cmd&lt;/span&gt; sync -M -m text/css --acl-public --add-header=&lt;span class=&quot;string&quot;&gt;&amp;quot;Cache-Control: max-age=60&amp;quot;&lt;/span&gt; &lt;span class=&quot;string escape&quot;&gt;\&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;string escape&quot;&gt;&lt;/span&gt;    _site/css s3://whycryptocurrencies.com/
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Although I’ve started to prefer Python for my scripts, I still have fond memories of when I wrote most of my scripts in Perl. There are things you can criticize Perl for, but it’s still one of the most fun programming languages I’ve used.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Unsolved-annoyances&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Unsolved-annoyances&quot; class=&quot;heading-ref&quot;&gt;Unsolved annoyances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are some things that doesn’t work as I want them to, but that I didn’t bother fixing.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Lack of routing control&lt;/p&gt;
&lt;p&gt;I complained about it in &lt;a href=&quot;/blog/2019/03/03/first_impressions_of_pollen/&quot; title=&quot;First impressions of Pollen&quot;&gt;first impressions post&lt;/a&gt;, but it still bothers me that chapters ends with &lt;code&gt;/private_money.html&lt;/code&gt; instead of &lt;code&gt;/private_money&lt;/code&gt;. But removing it completely would have me rewrite the auto reload system, so I have to live with this admittedly small annoyance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Slow&lt;/p&gt;
&lt;p&gt;Regenerating the book is pretty darn slow. I also have to clean the cache when I add or change Racket functions outside of chapters, which happens more often than I’d like.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;External styling script&lt;/p&gt;
&lt;p&gt;I wanted to use &lt;a href=&quot;https://sass-lang.com/&quot; title=&quot;Sass: CSS with superpowers&quot;&gt;Sass&lt;/a&gt; for styling and at first I tried to create a &lt;code&gt;main.css.p&lt;/code&gt; file that pipes out to &lt;code&gt;sassc&lt;/code&gt;, which is the way to generate arbitrary files with Pollen. I use this approach when I generate the xml feed, but I couldn’t get the reload to work properly so I just used an external script for it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;!/bin/bash&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;sassc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; sass/main.scss&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;style&lt;/span&gt; compressed &lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;gt;&lt;/span&gt; css/main.css&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function echo shell&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;created: css/main.css&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;inotifywait&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;e&lt;/span&gt; close_write,moved_to,create&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;m&lt;/span&gt; sass/&lt;/span&gt; &lt;span class=&quot;keyword operator logical pipe shell&quot;&gt;|&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control while shell&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function read shell&quot;&gt;read&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; &lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;-&lt;/span&gt;r&lt;/span&gt; directory events filename&lt;/span&gt;&lt;span class=&quot;keyword operator logical continue shell&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;keyword control do shell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;sassc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; sass/main.scss&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;style&lt;/span&gt; compressed &lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;gt;&lt;/span&gt; css/main.css&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function echo shell&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;updated: css/main.css&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control done shell&quot;&gt;done&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It uses &lt;code&gt;inotifywait&lt;/code&gt; to issue a command when files in the &lt;code&gt;sass/&lt;/code&gt; folder change. It can be found in the &lt;code&gt;inotify-tools&lt;/code&gt; package.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that’s it I think for the large part? I’m sure I missed something, but feel free to &lt;a href=&quot;https://codeberg.org/treeman/why_cryptocurrencies&quot; title=&quot;Source code to the book &apos;Why Cryptocurrencies?&apos;&quot;&gt;check out the source code&lt;/a&gt; if you’re curious about anything.&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Writing a Pollen lexer in Pygments</title><id>http://jonashietala.se/blog/2020/04/30/writing_a_pollen_lexer_in_pygments/index.html</id><updated>2023-10-13T17:36:38+00:00</updated><link href="https://www.jonashietala.se/blog/2020/04/30/writing_a_pollen_lexer_in_pygments" rel="alternate"/><published>2020-04-30T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After writing a &lt;a href=&quot;/blog/tags/pollen/&quot;&gt;few blog posts&lt;/a&gt; about Pollen I started getting annoyed that I didn’t have syntax highlighting for the code snippets. So I did a bit of fooling around with Pygments, and it turns out writing a custom lexer isn’t that unreasonable, so here’s how I did it.&lt;/p&gt;
&lt;h1&gt;Pollen markup&lt;/h1&gt;
&lt;p&gt;Pollen’s rules are pretty simple as it’s basically just some extra syntax for embedding Racket in a text file:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Comments starts with &lt;code&gt;◊;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;You can insert variables with &lt;code&gt;◊|my-var|&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run arbitrary Racket code with &lt;code&gt;◊( ... )&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;There’s an extra construction that transforms &lt;code&gt;◊fun[arg1 arg2]{some text}&lt;/code&gt; to &lt;code&gt;◊(fun arg1 arg2 &quot;some&quot; text&quot;)&lt;/code&gt;, which is useful when you want to send a bunch of interpolated text to a function. (I use it everywhere in &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;my book&lt;/a&gt;.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So the end goal is to be able to highlight this type of code:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;◊; A link can just be a standard reference
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;◊(define dune-audible &quot;https://www.audible.com/pd/Dune-Audiobook/B002V1OF70&quot;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;I&apos;m ◊strong{really} looking forward to the upcoming Dune movie!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;◊div[#:class &quot;extra-sand&quot;]{
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    I also recommend the Dune audiobook ◊link[#:ref dune-audible]{on Audible}.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Setup and parsing comments&lt;/h1&gt;
&lt;p&gt;The simpest &lt;a href=&quot;https://pygments.org/&quot;&gt;Pygments&lt;/a&gt; lexer might look like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import from python&quot;&gt;from&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;meta import-source python&quot;&gt; &lt;span class=&quot;meta import-path python&quot;&gt;&lt;span class=&quot;meta import-name python&quot;&gt;pygments&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt; &lt;span class=&quot;constant language import-all python&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import from python&quot;&gt;from&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;meta import-source python&quot;&gt; &lt;span class=&quot;meta import-path python&quot;&gt;&lt;span class=&quot;meta import-name python&quot;&gt;pygments&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;token&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt; &lt;span class=&quot;constant language import-all python&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta class python&quot;&gt;&lt;span class=&quot;storage type class python&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;entity name class python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;PollenLexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta class inheritance python&quot;&gt;&lt;span class=&quot;punctuation section inheritance begin python&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta class inheritance python&quot;&gt;&lt;span class=&quot;entity other inherited-class python&quot;&gt;RegexLexer&lt;/span&gt;&lt;span class=&quot;punctuation section inheritance end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta class python&quot;&gt;&lt;span class=&quot;punctuation section class begin python&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block documentation python&quot;&gt;&lt;span class=&quot;punctuation definition comment begin python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Lexer for Pollen
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation definition comment end python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;name&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;Pollen&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;aliases&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;pollen&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;filenames&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;*.html.pm&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;tokens&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta structure dictionary-or-set python&quot;&gt;&lt;span class=&quot;punctuation section dictionary-or-set begin python&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary-or-set python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section dictionary-or-set end python&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which if placed in &lt;code&gt;pollen.py&lt;/code&gt; can be run on a file &lt;code&gt;pollen.html.pm&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;python3&lt;/span&gt; -m pygments -l pollen.py:PollenLexer -x -f html pollen.html.pm
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That produces html output. Right now it doesn’t do anything interesting, as it only returns a &lt;code&gt;Text&lt;/code&gt; token for everything, so let’s change that shall we?&lt;/p&gt;
&lt;p&gt;I would like to support highlighting comments:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;◊; Standard comment
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Regular text ◊; Trailing comment
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which should be pretty straightforward. We just need to add a single clause to the root state that matches everything from &lt;code&gt;◊;&lt;/code&gt; to the end of the line:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;tokens&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta structure dictionary-or-set python&quot;&gt;&lt;span class=&quot;punctuation section dictionary-or-set begin python&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;◊;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;*?&lt;/span&gt;&lt;span class=&quot;keyword control anchor regexp&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Comment&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And comments are highlighted!&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;python3&lt;/span&gt; -m pygments -l pollen2.py:PollenLexer -x -f html pollen.html.pm
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;◊; Standard comment&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Regular text &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;◊; Trailing comment&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s hard to read so I’ll embed the output from now on:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/pollen_rework/comment.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;If you’re reading this but don’t understand why it works you might want to lookup &lt;a href=&quot;https://docs.python.org/3/library/re.html&quot;&gt;regular expressions in Python&lt;/a&gt;, in this post I’ll assume you’re familiar.&lt;/p&gt;
&lt;h1&gt;Embedding variables&lt;/h1&gt;
&lt;p&gt;Let’s move on to embedding variables via &lt;code&gt;◊|var|&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A first attempt could be like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;◊&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;\w&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which splits out highlighting into three groups; &lt;code&gt;◊|&lt;/code&gt;, &lt;code&gt;var&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt; and gives them different tokens using the special &lt;code&gt;bygroups&lt;/code&gt; construction. The tokens you choose are slightly arbitrary, but should generally follow the advice in &lt;a href=&quot;https://pygments.org/docs/tokens/&quot; title=&quot;Pygments tokens&quot;&gt;Pygments tokens reference&lt;/a&gt;. I chose &lt;code&gt;Name.Variable.Magic&lt;/code&gt; instead of something like &lt;code&gt;Punctuation&lt;/code&gt; because I wanted them to stand out more.&lt;/p&gt;
&lt;p&gt;This works, but there are two changes I’d like to make. The immediate problem is that we now only match against characters with &lt;code&gt;\w+&lt;/code&gt;, but a Racket variable can contain a bunch of different symbols. This is for example perfectly valid:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;a2-!&lt;/span&gt;+*# &lt;span class=&quot;constant numeric pollen&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;a2-!&lt;/span&gt;+*#&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we look at the &lt;a href=&quot;https://github.com/pygments/pygments/blob/master/pygments/lexers/lisp.py#L459&quot; title=&quot;RacketLexer on Github&quot;&gt;existing Racket lexer&lt;/a&gt; they have defined a variable like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;valid_symbol_chars&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class begin regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;\w&lt;/span&gt;!$%*+,&amp;lt;=&amp;gt;?/&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\&amp;#39;&lt;/span&gt;@&amp;amp;#:-&lt;span class=&quot;punctuation definition character-class end regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class begin regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other character-class range regexp&quot;&gt;A-Z&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class end regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;%s&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;valid_symbol_chars&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which we can steal and copy to our class and use when we build our regex:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;◊&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;%s&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make this work out of the box we also need to add the regex flags:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;flags&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;IGNORECASE&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;MULTILINE&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The other thing I want to do is introduce another state. It’s not strictly needed in this case, but as &lt;code&gt;◊&lt;/code&gt; can be followed by different cases it makes the lexer easier to follow. Like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;◊;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;*?&lt;/span&gt;&lt;span class=&quot;keyword control anchor regexp&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Comment&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;◊&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-magic&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-magic&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;%s&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now what happens when we parse the &lt;code&gt;◊&lt;/code&gt; we mark it as &lt;code&gt;Name.Variable.Magic&lt;/code&gt; and the push the state &lt;code&gt;post-magic&lt;/code&gt; onto the stack. Important to note is that we don’t replace the existing state, so the stack will now have &lt;code&gt;post-magic&lt;/code&gt; on top and &lt;code&gt;root&lt;/code&gt; below.&lt;/p&gt;
&lt;p&gt;Then when we try to parse the next character, &lt;code&gt;post-magic&lt;/code&gt; is responsible to match against it. The new thing there is the magic &lt;code&gt;&apos;#pop&apos;&lt;/code&gt; variable that pops from the stack, so after we’re done matching &lt;code&gt;◊|var|&lt;/code&gt; we hand back control to &lt;code&gt;root&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This should now be able to highlight embedding variables:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/pollen_rework/vars.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;I unfortunately didn’t figure out how to debug the state transitions in an easy manner. If we mess up Pygments will insert &lt;code&gt;err&lt;/code&gt; classes but you can also play around with different colored tokens during development, for example letting &lt;code&gt;root&lt;/code&gt; return a &lt;code&gt;Keyword&lt;/code&gt; token so you can see that we return to the right state.&lt;/p&gt;
&lt;h1&gt;Highlighting Racket code&lt;/h1&gt;
&lt;p&gt;Our next step is to try to highlight Racket code inside &lt;code&gt;◊( ... )&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I thought this was going to be really hard, but Pygments supports this in various ways. The way I chose was to delegate the lexer of different parts to the existing &lt;code&gt;RacketLexer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First the import:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import from python&quot;&gt;from&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;meta import-source python&quot;&gt; &lt;span class=&quot;meta import-path python&quot;&gt;&lt;span class=&quot;meta import-name python&quot;&gt;pygments&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;lexers&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;lisp&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt; &lt;span class=&quot;meta generic-name python&quot;&gt;RacketLexer&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the case is simply:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-magic&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant language python&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;using&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;RacketLexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable parameter python&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;unquoted-datum&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The interesting line is &lt;code class=&quot;highlight python&quot;&gt;&lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;using&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;RacketLexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable parameter python&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;unquoted-datum&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; which delegates the lexer to &lt;code&gt;RacketLexer&lt;/code&gt;, starting in state &lt;code&gt;unquoted-datum&lt;/code&gt;. How did I figure out which initial state to start in? I tried to &lt;a href=&quot;https://github.com/pygments/pygments/blob/master/pygments/lexers/lisp.py#L459&quot; title=&quot;RacketLexer on Github&quot;&gt;read the code&lt;/a&gt; and make an educated guess…&lt;/p&gt;
&lt;p&gt;But we also need to ensure we use the regex flag of allowing the dot to match newlines as well, otherwise we won’t match multiline racket expressions:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;flags&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;IGNORECASE&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;DOTALL&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;MULTILINE&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And all embedded Racket code is highlighted:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/pollen_rework/racket.png&quot; /&gt;
&lt;/figure&gt;
&lt;h1&gt;Recursive brackets&lt;/h1&gt;
&lt;p&gt;Now lexing &lt;code&gt;◊var[arg1]{text args}&lt;/code&gt; is a bit more involved, but builds on the concepts we’ve already seen.&lt;/p&gt;
&lt;p&gt;First let’s support the simpler &lt;code&gt;◊var{text args}&lt;/code&gt; case.&lt;/p&gt;
&lt;p&gt;Matching &lt;code&gt;◊var&lt;/code&gt; is straightforward:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-magic&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant language python&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We could do more here, but we’re preparing for the future where we can also match against an optional &lt;code&gt;[...]&lt;/code&gt; after the variable, so we’ll delegate to another state. &lt;code class=&quot;highlight python&quot;&gt;&lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; essentially means we’ll replace the current state &lt;code&gt;post-magic&lt;/code&gt; with the new &lt;code&gt;curly-start&lt;/code&gt; state.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-end&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here again we could’ve done more, but we want to be able to do recursive matching inside &lt;code&gt;{ ... }&lt;/code&gt; as well. This is what the &lt;code&gt;curly-end&lt;/code&gt; state does:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-end&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;include&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;include&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; does what you might expect it to do: it copies all cases from our &lt;code&gt;root&lt;/code&gt; state into the &lt;code&gt;curly-end&lt;/code&gt; sate. This to avoid code duplication.&lt;/p&gt;
&lt;p&gt;And this can indeed highlight &lt;code&gt;◊var{ ... }&lt;/code&gt; recursively!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/pollen_rework/var_rec.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;To support an optional &lt;code&gt;[ ... ]&lt;/code&gt; we can add another state before &lt;code&gt;curly-end&lt;/code&gt; that either matches against square brackets or curly brackets:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-magic&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;constant language python&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-var&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-var&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator annotation variable python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\[&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;+?&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\]&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                    &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;using&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;RacketLexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable parameter python&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;unquoted-datum&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;include&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ve already seen these things before. The only thorn in my side here is that we use a non-greedy match &lt;code&gt;(.+?)&lt;/code&gt; to match between brackets, but we used a greedy &lt;code&gt;(.+)&lt;/code&gt; earlier. I don’t have a good answer for this… This could probably be improved some way.&lt;/p&gt;
&lt;p&gt;But hey! Think positive! It works for the cases I need. For example:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/pollen_rework/div_rec.png&quot; /&gt;
&lt;/figure&gt;
&lt;h1&gt;The result&lt;/h1&gt;
&lt;p&gt;Putting it all together we can now highlight the code we looked at in the start of this post:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/pollen_rework/big_res.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;And this is the complete lexer:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;python&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight python&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import from python&quot;&gt;from&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;meta import-source python&quot;&gt; &lt;span class=&quot;meta import-path python&quot;&gt;&lt;span class=&quot;meta import-name python&quot;&gt;pygments&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;lexer&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt; &lt;span class=&quot;constant language import-all python&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import from python&quot;&gt;from&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;meta import-source python&quot;&gt; &lt;span class=&quot;meta import-path python&quot;&gt;&lt;span class=&quot;meta import-name python&quot;&gt;pygments&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;token&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt; &lt;span class=&quot;constant language import-all python&quot;&gt;*&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import from python&quot;&gt;from&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;meta import-source python&quot;&gt; &lt;span class=&quot;meta import-path python&quot;&gt;&lt;span class=&quot;meta import-name python&quot;&gt;pygments&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;lexers&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta import-name python&quot;&gt;lisp&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta statement import python&quot;&gt; &lt;span class=&quot;meta generic-name python&quot;&gt;RacketLexer&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta statement import python&quot;&gt;&lt;span class=&quot;keyword control import python&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta class python&quot;&gt;&lt;span class=&quot;storage type class python&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;entity name class python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;PollenLexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta class inheritance python&quot;&gt;&lt;span class=&quot;punctuation section inheritance begin python&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta class inheritance python&quot;&gt;&lt;span class=&quot;entity other inherited-class python&quot;&gt;RegexLexer&lt;/span&gt;&lt;span class=&quot;punctuation section inheritance end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta class python&quot;&gt;&lt;span class=&quot;punctuation section class begin python&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block documentation python&quot;&gt;&lt;span class=&quot;punctuation definition comment begin python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Lexer for Pollen
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation definition comment end python&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;name&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;Pollen&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;aliases&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;pollen&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;filenames&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;*.html.pm&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;flags&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;IGNORECASE&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;DOTALL&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;variable other constant python&quot;&gt;MULTILINE&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;valid_symbol_chars&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class begin regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;\w&lt;/span&gt;!$%*+,&amp;lt;=&amp;gt;?/&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\&amp;#39;&lt;/span&gt;@&amp;amp;#:-&lt;span class=&quot;punctuation definition character-class end regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant other character-class set regexp&quot;&gt;&lt;span class=&quot;punctuation definition character-class begin regexp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other character-class range regexp&quot;&gt;A-Z&lt;/span&gt;&lt;span class=&quot;punctuation definition character-class end regexp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;%s&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;valid_symbol_chars&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;tokens&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta structure dictionary-or-set python&quot;&gt;&lt;span class=&quot;punctuation section dictionary-or-set begin python&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;◊;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;*?&lt;/span&gt;&lt;span class=&quot;keyword control anchor regexp&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Comment&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;◊&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-magic&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Text&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary-or-set python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-magic&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;%s&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;using&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;RacketLexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable parameter python&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;unquoted-datum&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator arithmetic python&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-var&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary-or-set python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;post-var&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\[&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character character-class regexp&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;keyword operator quantifier regexp&quot;&gt;+?&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group regexp&quot;&gt;&lt;span class=&quot;punctuation definition group begin regexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\]&lt;/span&gt;&lt;span class=&quot;punctuation definition group end regexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;bygroups&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;using&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;RacketLexer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable parameter python&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;keyword operator assignment python&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;unquoted-datum&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator arguments python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                         &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;include&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary-or-set python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-start&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-end&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary-or-set python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;curly-end&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value python&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta structure list python&quot;&gt;&lt;span class=&quot;punctuation section list begin python&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group python&quot;&gt;&lt;span class=&quot;punctuation section group begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage type string python&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;source regexp python&quot;&gt;&lt;span class=&quot;constant character escape backslash regexp&quot;&gt;\}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Variable&lt;/span&gt;&lt;span class=&quot;punctuation accessor dot python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;meta generic-name python&quot;&gt;Magic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator tuple python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;#pop&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta function-call python&quot;&gt;&lt;span class=&quot;meta qualified-name python&quot;&gt;&lt;span class=&quot;variable function python&quot;&gt;include&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments begin python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function-call arguments python&quot;&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;&lt;span class=&quot;punctuation definition string begin python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta string python&quot;&gt;&lt;span class=&quot;string quoted single python&quot;&gt;root&lt;span class=&quot;punctuation definition string end python&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section arguments end python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator list python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation section list end python&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary-or-set python&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation section dictionary-or-set end python&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>Minor site updates</title><id>http://jonashietala.se/blog/2020/04/29/minor_site_updates/index.html</id><updated>2026-04-27T11:10:34+00:00</updated><link href="https://www.jonashietala.se/blog/2020/04/29/minor_site_updates" rel="alternate"/><published>2020-04-29T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;As it happens I got a little tired of the syntax highlighter Pandoc uses so on a whim I started looking at moving to Pygments as my highlighter. With some searching around I found a &lt;a href=&quot;https://jip.dev/posts/the-switch-to-hakyll/&quot;&gt;blog post&lt;/a&gt; about just that! That’s lucky because while I like Haskell, I’ve never &lt;em&gt;really&lt;/em&gt; grocked it and I’ve only dabbled enough with it to (mostly) make things work like I want to.&lt;/p&gt;
&lt;p&gt;Often I’ll get stuck longer than with any other language just trying to understand WTH is happening. See this snippet for example:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;responseLength &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;-&lt;/span&gt; read &lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;constant other haskell&quot;&gt;U8&lt;/span&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt;toString &lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt; fromJust &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (&lt;span class=&quot;constant other haskell&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt;lines &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;constant other haskell&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt;read) is
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What did &lt;code&gt;.&lt;/code&gt; do again? And the &lt;code&gt;&amp;lt;$&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;gt;=&amp;gt;&lt;/code&gt; have something to do with monads…&lt;/p&gt;
&lt;p&gt;Even though I figured it out after a while, getting stuck on surface level things like this really makes me wonder if it wouldn’t be better to just rewrite the site in some other language.&lt;/p&gt;
&lt;p&gt;Or put more effort into actually learning Haskell. Maybe the next time…&lt;/p&gt;
&lt;h1&gt;Highlighting code via Pygments&lt;/h1&gt;
&lt;p&gt;The core idea of the Pygments implementation is to reroute all parsing of code elements out to a separate process. For speed reasons it’s implemented as a long running process instead of calling out to the shell all the time.&lt;/p&gt;
&lt;p&gt;I didn’t come up with the approach, but I did some changes to it. One of them was to highlight both code blocks and inline code. The core transform function gets called by overriding the pandoc compiler:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;pandocCompiler&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Streams&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Compiler&lt;/span&gt; (&lt;span class=&quot;storage type haskell&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pandocCompiler streams &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  pandocCompilerWithTransformM defaultHakyllReaderOptions
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                               defaultHakyllWriterOptions
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                               (pygments streams)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The transformer simply walks over blocks, matches against code and passes the content to the pygments process in &lt;code&gt;streams&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;pygments&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Streams&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Pandoc&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Compiler&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Pandoc&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pygments streams &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;walkM (generateCodeBlock streams)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;generateCodeBlock&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Streams&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Block&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Compiler&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Block&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;generateCodeBlock streams (CodeBlock (_, classes, keyvals) contents) &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword other haskell&quot;&gt;let&lt;/span&gt; lang &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; unpackLang classes keyvals
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  code &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;-&lt;/span&gt; highlightCode streams lang contents
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  return &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;constant other haskell&quot;&gt;RawBlock&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;html&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; pack &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; renderHtml &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;constant other haskell&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt;pre &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; hCode lang code
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The thing I added was a clause to walk over inline elements as well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;generateCodeBlock streams x &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; walkM (generateCodeInline streams) x
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;generateCodeInline&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Streams&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Inline&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Compiler&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Inline&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;generateCodeInline streams (Code (_, classes, keyvals) contents) &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword other haskell&quot;&gt;let&lt;/span&gt; lang &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; unpackLang classes keyvals
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  code &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;-&lt;/span&gt; highlightCode streams lang contents
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  return &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;constant other haskell&quot;&gt;RawInline&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;html&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; pack &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; renderHtml &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; hCode lang code
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;generateCodeInline _ x &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; return x
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Updated gruvbox syntax highlighting&lt;/h1&gt;
&lt;p&gt;Pygments use a different markup, so I had to update my gruvbox inspired css scheme. It’s not perfect, and the choices are arbitrary, but I think the output is fairly good. If you’re interested the stylesheet itself, see the sources for &lt;a href=&quot;https://codeberg.org/treeman/jonashietala/src/branch/master/css/gruvbox.scss&quot;&gt;gruvbox.scss&lt;/a&gt; and &lt;a href=&quot;https://codeberg.org/treeman/jonashietala/src/branch/master/css/code.scss&quot;&gt;code.scss&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Git commit hash in post footers&lt;/h1&gt;
&lt;p&gt;Another pretty cool idea I got from the blog post was embedding a git commit hash in the footer of each post. It’s probably not particularly useful, but it was a fun idea nonetheless.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/commit_footer.png&quot; /&gt;
&lt;figcaption&gt;This is how it looks when embedded. Clicking on it takes you to the history of the post file.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The idea is to use &lt;code&gt;readProcess&lt;/code&gt; and &lt;code&gt;unsafeCompiler&lt;/code&gt; to launch a git process to retrieve info. Something like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;gitTag&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;gitTag key &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;field key &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;\&lt;/span&gt;item &lt;span class=&quot;keyword operator haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword other haskell&quot;&gt;let&lt;/span&gt; fp &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; (toFilePath &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; itemIdentifier item)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      gitLog format &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        readProcess &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;git&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; [
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;log&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;-1&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;HEAD&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;--pretty=format:&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;++&lt;/span&gt; format
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;--date=format:%b %e, %Y&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; fp
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ] &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  unsafeCompiler &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    sha     &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;-&lt;/span&gt; gitLog &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;%h&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    message &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;-&lt;/span&gt; gitLog &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;%s&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    date    &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;-&lt;/span&gt; gitLog &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;%ad&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword operator haskell&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And add it to post contexts:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;postCtx tags &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; mconcat
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    [ siteCtx
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; gitTag &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;git&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator haskell&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ]
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again, not my idea.&lt;/p&gt;
</content></entry><entry><title>My book &apos;Why Cryptocurrencies?&apos; is done</title><id>http://jonashietala.se/blog/2020/04/29/my_book_why_cryptocurrencies_is_done/index.html</id><updated>2024-06-27T07:48:43+00:00</updated><link href="https://www.jonashietala.se/blog/2020/04/29/my_book_why_cryptocurrencies_is_done" rel="alternate"/><published>2020-04-29T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;My first commit on my book &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;Why Cryptocurrencies?&lt;/a&gt; is from Dec 19, 2018, and now about 17 months later and 1006 more commits I’m finally done!&lt;/p&gt;
&lt;p&gt;Well, I’m done with the online version at least. I still plan to create an e-book, a PDF and a paperback and who knows how long that will take? It would be great to have a physical copy in my hands in 2020, but as I’ve never done these things before I don’t know if that’s a realistic expectation or not. Especially as I only work on it a little here and there—we did get our second kid in February after all!&lt;/p&gt;
&lt;p&gt;Anyhow it’s &lt;a href=&quot;https://whycryptocurrencies.com/&quot; title=&quot;Why Cryptocurrencies?&quot;&gt;available online for free&lt;/a&gt; and I’m actually quite proud of what I’ve accomplished. It doesn’t really matter if it’s not successful and if I won’t get financially rewarded for the time I’ve spent, because I did my best and I think it came out nicely.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/whycrypto/ex_money.png&quot; /&gt;
&lt;figcaption&gt;A screenshot of the chapter “What is money?”&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I didn’t track exactly how much time I spent writing, I find it difficult to track my time on such a granular level, but I’ve tried hard to write an hour every weekday before work. I even started working 80% at my job so I could focus on writing a bit more and to be home with my family more.&lt;/p&gt;
&lt;p&gt;And on that note working 1–2 hours less, which if you work from home and don’t have to commute can turn into 2–3 hours, is &lt;strong&gt;absolute gold&lt;/strong&gt;. I honestly don’t know if I could ever go back to working full-time with a 30 min commute as I did before, the difference in quality of life is just so great.&lt;/p&gt;
&lt;p&gt;At first I tried to work 4 days a week, and use the fifth to focus on writing, but I didn’t really feel it worked well for me. Sure I was very productive the day I focused on my project, but then I had to wait a whole week until I could do it again, and then it felt quite difficult to get my mind to it again. Of course I could’ve written before or after work as well, but my brain is just exhausted after working 8 hours so in practice it was too difficult to keep up.&lt;/p&gt;
&lt;p&gt;It worked &lt;em&gt;much better&lt;/em&gt; to always do something, even if it’s just small and if I just spent 30 min or even 15 min each day writing, I felt like I could go much further than when I tried to write in big batches. I know this isn’t unique and “write a little every day” is a very common advice for writers, and for good reason I’d say.&lt;/p&gt;
&lt;p&gt;As a final note on word count: I never counted how many words I wrote each day, how many I had written and I never had a target I was aiming at. I just tried to write down what I had to say, without padding it too much or cutting my message short.&lt;/p&gt;
&lt;p&gt;As I wrote my book in &lt;a href=&quot;https://docs.racket-lang.org/pollen/&quot; title=&quot;Pollen: the book is a program&quot;&gt;Pollen&lt;/a&gt;, which mixes text with markup and source code, it’s not so easy to get a reliable word count. When counting the output html files with &lt;code class=&quot;highlight fish&quot;&gt;&lt;span class=&quot;function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;s/&amp;lt;[^&amp;gt;]*&amp;gt;//g&amp;quot;&lt;/span&gt; eli5.html &lt;span class=&quot;operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;wc&lt;/span&gt; -c
&lt;/code&gt; I come up with these numbers:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt; 31578 how_do_cryptocurrencies_work.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 29690 uncensorable_donations.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 29602 private_money.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 26867 a_defective_system.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 25799 financial_crisis.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 23652 voting.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 23361 what_is_money.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 21181 challenges.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 19292 protection_against_government_confiscation.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 17044 timestamping_service.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 16843 global_currency.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 16628 for_the_unbanked.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 16595 cryptography.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 16401 the_blind_leading_the_blind.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 15534 cashless_dystopia.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 15415 cheaper_faster.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 15151 are_cryptocurrencies_money.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 14922 swiss_bank_account_in_your_pocket.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 13174 darknet_markets.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 12088 undesirable_businesses.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 11909 tokens.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 10850 separation_of_money_and_state.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  9837 provably_fair_gambling.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  9733 uncensorable_twitter.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  8868 properties_of_a_cryptocurrency.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  8641 freezing_of_merchant_accounts.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  8418 about_the_book.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  7507 look_out_for_snake_oil.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  6403 extensions.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  4383 about_me.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  3885 brave_new_world.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  3849 eli5.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  3138 bitcoin_whitepaper.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  2933 how_to_use.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  2696 better_currency.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  2396 free.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  2360 better_digital_payments.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  2186 what_is_a_cryptocurrency.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  1323 index.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  1309 acknowledgements.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   845 appendix.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   712 error.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;514998
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So according to this the book is &lt;strong&gt;514 998&lt;/strong&gt; words long. That’s… really a lot. Advice on the internet seems to suggest around 100 000 words is the upper recommended limit for most, so I have a hard time believing I’m doing this correctly. This way of counting overestimates it, but I haven’t bothered to figure out how much. I guess I’ll see when I try to actually make a book or a PDF out of it.&lt;/p&gt;
&lt;p&gt;How much source code did I write? That’s also difficult to say, as some of it is mixed in the chapter files, but for the pure code files this is the result:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;wc&lt;/span&gt; -l **.rkt
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;number&quot;&gt;1735&lt;/span&gt; total
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;fish&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight fish&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;wc&lt;/span&gt; -l **.scss
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;number&quot;&gt;1702&lt;/span&gt; total
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So around 1735 lines in Racket and 1702 lines in Sass. Kind of interesting how the styling corresponds to almost as much code as the layout formatting does.&lt;/p&gt;
&lt;p&gt;My experience with the technologies I used has been quite positive, but I plan to write about it more in detail in a future post.&lt;/p&gt;
</content></entry><entry><title>2019 in Review</title><id>http://jonashietala.se/blog/2019/12/25/2019_in_review/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/12/25/2019_in_review" rel="alternate"/><published>2019-12-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;As &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly reviews&quot;&gt;is tradition&lt;/a&gt; a quick rundown of the year is due. It’s been good to do as it makes me reflect on the past year, and see that I did indeed do some things, and to look ahead a little.&lt;/p&gt;
&lt;h1&gt;2019 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Played around with Isidor.&lt;/p&gt;
&lt;p&gt;It’s hard to describe how happy a kid can make you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a bunch of books.&lt;/p&gt;
&lt;p&gt;I like the idea of tracking all the books I read. But I hate the actual tracking part, so I don’t actually know what books I did read. &lt;a href=&quot;https://www.goodreads.com/book/show/26889576-the-big-short&quot;&gt;The Big Short&lt;/a&gt;, &lt;a href=&quot;https://www.goodreads.com/book/show/46223297-permanent-record&quot;&gt;Permanent Record&lt;/a&gt; and &lt;a href=&quot;https://www.goodreads.com/book/show/35606041-a-little-hatred&quot;&gt;A Little Hatred&lt;/a&gt; are some I read recently, and they’re great.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Regular grappling training.&lt;/p&gt;
&lt;p&gt;Since we moved, I’ve only been training grappling very rarely. But now I train Submission Wrestling here once a week. I &lt;strong&gt;love&lt;/strong&gt; it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Built a small home gym.&lt;/p&gt;
&lt;p&gt;It’s a real luxury.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2019 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Started &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;writing a book&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So far I’ve written around 80% of the planned chapters, so I guess there’s only around 80% of the work left. I’ve managed to produce a bunch of words:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;&gt; wc -c *.html.pm | sort -n
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;402050 total
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(It’s an overestimation, but it gives a rough estimate.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Did some memory training.&lt;/p&gt;
&lt;p&gt;I had a goal of becoming better at memorizing things. Like a deck of cards or better at learning a new language. I haven’t done a lot, but it clearly works (although the training is very mentally draining).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote a &lt;a href=&quot;/blog/2019/04/17/picking_up_rust_by_writing_a_qr_code_generator/&quot;&gt;QR code generation in Rust&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some Racket.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Assembled my &lt;a href=&quot;https://input.club/devices/infinity-ergodox/&quot;&gt;Ergodox Infinity&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Built a bunch of Lego.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2019 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;I wanted to have come further with the memory training.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2020&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Adjust to a new family member, expected in February.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finish my book.&lt;/p&gt;
&lt;p&gt;I can at least finish the writing part, and probably produce a pdf/ebook/epub or whatever digital format is the fashion nowadays. The ultimate goal is to get a physical book in my bookshelf, but I have no idea how long that process might be.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complete enough of the memory training to start learning a new language.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go through the book &lt;a href=&quot;https://shop.jcoglan.com/building-git/&quot;&gt;building git&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read some books.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/IMG_20191225_114508_2.jpg&quot; /&gt;
&lt;figcaption&gt;Books I didn’t read in 2019 that I want to read in 2020.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And then some books I want to re-read:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A Song of Ice and Fire series&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Assuming&lt;/em&gt; the new Game of Thrones book gets released in 2020…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The books in the First Law World&lt;/p&gt;
&lt;p&gt;I regret I didn’t re-read the books before I read A Little Hatred, which is the first book in the new trilogy in the world. The other books are to be released in November 2020 and 2021, and Joe Abecrombie did a good job by writing the story of the whole trilogy before even realising the first book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dune&lt;/p&gt;
&lt;p&gt;I should prepare for the movie that’s coming in 2020 by re-reading the classic book, which I don’t really remember other than it being very good.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a whole lot of books for me, as I don’t usually read that much. Maybe I need to stop reading so much manga, or lower my expectations a bit. I should be happy if I go through even a third of this list.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It was a pretty good year. Looking forward to an even better one next year.&lt;/p&gt;
</content></entry><entry><title>A friendly game of Twilight Imperium</title><id>http://jonashietala.se/blog/2019/12/11/a_friendly_game_of_twilight_imperium/index.html</id><updated>2024-06-27T07:48:25+00:00</updated><link href="https://www.jonashietala.se/blog/2019/12/11/a_friendly_game_of_twilight_imperium" rel="alternate"/><published>2019-12-11T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A few weeks ago I played my first game of Twilight Imperium (Fourth Edition). It was &lt;em&gt;fantastic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We were six players, most had played the third edition before. As I was quite hyped before the game, I had read up on the rules, watched a let’s play or two and listened to &lt;a href=&quot;https://spacecatspeaceturtles.podbean.com/&quot;&gt;a podcast dedicated to the game&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(This is a bit of a play recap, so if you don’t know anything about the game you might be confused.)&lt;/p&gt;
&lt;h1&gt;The setup&lt;/h1&gt;
&lt;p&gt;We had a standard map, so everyone had a decent pie slice. We randomized the places and I got one with a clear path to Mecatol Rex, but I didn’t think I would ever get there.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ti/IMG_20191124_110449.jpg&quot; /&gt;
&lt;figcaption&gt;The map.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Each player could choose between two random factions, my choice was between The Universities of Jol-Nar and The Mentak Coalition. I was fairly lucky, since before the game I had a few factions I wanted to play (Jol-Nar, Hacan, the Barony and Nekro Virus), and besides many people say Jol-Nar is a pretty good faction, so the choice was easy for me.&lt;/p&gt;
&lt;p&gt;The other chosen factions were The Embers of Muaat and The Yin Brotherhood, who were my neighbours, and The Naalu Collective, The Barony of Letnev and The Nekro Virus. I was thinking the Naalu would have a good shot, since the person who plays them is a bit of a power gamer (I do have a little power gamer in myself as well).&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ti/IMG_20191124_114812_825.jpg&quot; /&gt;
&lt;figcaption&gt;The beautiful starting units of The Muaat.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/ti/IMG_20191124_110500.jpg&quot; /&gt;
&lt;figcaption&gt;The Muaat player’s reserve units.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/ti/20191124_130444.jpeg&quot; /&gt;
&lt;figcaption&gt;Ready for action.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Early game&lt;/h1&gt;
&lt;p&gt;We went through the rules and then we went out for lunch. As the shady person that I am, I spent some time trying to convince my Muaat neighbour we should be trade buddies, and maybe even trade support for the throne (to give each other a victory point, which we’ll lose if we attack each other).&lt;/p&gt;
&lt;p&gt;He was a little reluctant, but we did establish a pretty great trade relationship. Each of us picked Trade several times, and we always traded everything we could. We didn’t trade support for the throne, but we did trade a ceasefire.&lt;/p&gt;
&lt;p&gt;Instead I traded support for the throne with my other neighbour, the Yin Brotherhood. And I also gave him the faction promissory note, which I sold to anyone who wanted it. I heard the phrase “feed everyone, which will feed yourself” in the podcast, which I tried to embrace as much as I could.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ti/IMG_20191124_140642_407.jpg&quot; /&gt;
&lt;figcaption&gt;Movements during the first round. I’m yellow, the Yin is purple, the Barony red, the Naalu black, the Nekro Virus green and the Muaat is blue.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Altogether I had a &lt;em&gt;fantastic&lt;/em&gt; early game. I had made peace with both of my neighbours, and I was getting a ton of money.  I even scored a few early points, keeping me in the lead or tied with the leader.&lt;/p&gt;
&lt;h1&gt;Mid game&lt;/h1&gt;
&lt;p&gt;My good luck continued. I kept getting more money while avoiding conflict, and I had built up a pretty sizeable fleet. I was a bit confused though, because I had heard on the podcast that rushing to Mecatol Rex was a common strategy, and several people in our group even said that they wanted to take it early. But none had done this so far.&lt;/p&gt;
&lt;p&gt;So that’s what I did. And I had a big enough fleet to hold it, probably for a couple of rounds. I did make a mistake though—I left the planet closest to Mecatol empty and my neighbour, my friend and ally, parked a stupid looking ship there. Which I of course couldn’t attack without losing a victory point (grumble, grumble).&lt;/p&gt;
&lt;p&gt;I was really scared of holding it, because I was spreading myself fairly thin and I was expecting people to build up their death balls and root me up. So I started reinforcing it with PDS’s and built more units via a space dock I placed there.&lt;/p&gt;
&lt;p&gt;All the while I was still trading, and making good deals. I also got the tech where I get four trade goods whenever anyone activates my system, and I had an open deal to anyone that they could activate a system of mine and I would give them three of the trade goods (keeping one for myself). With this I was able to have the biggest death ball on the board, sitting on Mecatol Rex.&lt;/p&gt;
&lt;p&gt;By this time I had made a deal with the Naalu for their promissory note (which I’ve heard is &lt;em&gt;extremely&lt;/em&gt; good—game winning good) for my promissory note, telling him I would be researching War Suns. I was thinking I should &lt;strong&gt;not&lt;/strong&gt; go for War Suns… But I was sitting pretty on Mecatol, thinking I could build a bigger death ball than anyone and then cruise to victory. So this is what I did, I built a War Sun and I felt I had a huge lead.&lt;/p&gt;
&lt;h1&gt;Late game&lt;/h1&gt;
&lt;p&gt;My main worry was the Yin flagship. Which, if you’re not familiar, will blow up &lt;em&gt;everything&lt;/em&gt; when it dies. So even if we were allies for now, if I ran away with the game too much he could just decide to say fuck it and nuke my fleet (which he after the game admitted was his plan all along). This is why I was actually planning to move away with my fleet, and just leave some ships and a ton of ground troops to defend it.&lt;/p&gt;
&lt;p&gt;But the Naalu guy appeared to save me. He went for a suicide mission to kill the flagship (earning a victory point) and made me relax. In a funny trade he then gave the Yin enough resources to rebuild the flagship… But I figured I had a small window to breath in.&lt;/p&gt;
&lt;p&gt;Of course, then the real disaster struck. I didn’t know this, but there’s an Agenda that players can vote on, and if it passes there’s a 50% chance everything on Mecatol Rex will be wiped out. And it popped up, and of course everyone voted for it to pass. And &lt;strong&gt;of course&lt;/strong&gt; my death ball got completely destroyed, and I lost control of Mecatol.&lt;/p&gt;
&lt;p&gt;(It’s my eternal regret that I didn’t take a picture of this amazing moment.)&lt;/p&gt;
&lt;p&gt;It’s pretty cool that something like this can happen… But I wasn’t very happy at that time. In fact I was quite unhappy (fucking idiotic game!!), and it seemed like the game had slipped out of my hands.&lt;/p&gt;
&lt;p&gt;I struggled on, and somehow, I was still in the game. My fleet was growing, and I had Dreadnaughts with great upgrades, and I could even reclaim my planet next to Mecatol from my “ally” who had parked there for most of the game (we still had each other’s support for the king though). Disappointingly for me we had only a single research objective, but I was still tied for the lead.&lt;/p&gt;
&lt;p&gt;The last round came around, and I stole the Naalu zero initiative token. The Naalu however could’ve still won with Imperial (which he had taken many times during the game, something I should’ve prioritized more) but the Nekro used an action card to force him to change (which he btw stole from me). This was quite upsetting to the Naalu—who really hates kingmakers—so he decided to take over his home planet, for revenge I assume, instead of taking my home planet.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ti/IMG_20191124_202903.jpg&quot; /&gt;
&lt;figcaption&gt;Action during the final round.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the end I had a small chance of victory: to take control over four hazardous planets, and I had only three. I tried to stall out, but was running out of command counters, so I had to take a shot. I took a system across the board, to get me my four planets, but the Naalu guy could still attack me and kill me. (If I had planned better I could’ve taken an extra planet from the same system, but I had only a single infantry.) He thought he could attack me later, so he did something else first. But I had an action card to place one of his tokens there, making him unable to attack that system.&lt;/p&gt;
&lt;p&gt;I thought I’d won, but I told him my winning condition (BIG mistake) so he made a last ditch effort to take back one of my hazardous planets. I managed to defend, thanks to a research I had which we both had forgotten about. And thanks to the Naalu token I was allowed to score first and snag the win. The token really was game winning.&lt;/p&gt;
&lt;p&gt;The really good thing about this game was that 3-4 people could’ve won this round, and it all came down to initiative order. Very close game, and &lt;em&gt;extremely&lt;/em&gt; fun (it would’ve been fun even if I didn’t win mind you).&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ti/IMG_20191124_203253371.jpg&quot; /&gt;
&lt;figcaption&gt;The state of the galaxy at the end of the game.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/ti/IMG_20191124_203306853.jpg&quot; /&gt;
&lt;figcaption&gt;The ending score. Jol-Nar at 10, Barony and Naalu at 8, Muaat and Yin at 6 and Nekro Virus at 5.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’m so looking forward to the next time I get to play this game.&lt;/p&gt;
</content></entry><entry><title>We moved away from the city</title><id>http://jonashietala.se/blog/2019/10/18/we_moved_away_from_the_city/index.html</id><updated>2024-06-27T07:48:36+00:00</updated><link href="https://www.jonashietala.se/blog/2019/10/18/we_moved_away_from_the_city" rel="alternate"/><published>2019-10-18T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;When me and my girlfriend Veronica moved to Linköping to study at the University the plan was never to stay there permanently. We just moved there to study but the longterm plan, if you can have one at that stage, was always to move back to the north of Sweden where we came from.&lt;/p&gt;
&lt;p&gt;After 8 years in Linköping we’ve now lived a little more than a year in a small community in the north of Sweden, so here’s some of the experience of moving away from the city out to “nowhere”.&lt;/p&gt;
&lt;h1&gt;Getting a remote job&lt;/h1&gt;
&lt;p&gt;We liked Linköping more than we thought, so when we were finished with our studies after five years we stayed and found some work. Veronica started teaching at a school nearby and I got a job as a software developer, at the place I had interned twice before.&lt;/p&gt;
&lt;p&gt;Before I was finished with school and before starting to look for work the boss at the company contacted me and wanted to hire me. At least I hadn’t made a fool out of myself during my time there. As the plan was still to eventually move north again I made this clear from day one and asked about the possibility of remote work. While it wasn’t something they usually allowed, we agreed that if I worked 2 years locally and showed I was capable it should be possible.&lt;/p&gt;
&lt;p&gt;Taking the promise in good faith, and as I liked my time there, I accepted the offer. After all I could always try to find a new job if the remote option wasn’t on the table when we decided to move.&lt;/p&gt;
&lt;p&gt;When the time finally came for us to plan our move up north, it wasn’t just for me to start working remotely (as you might expect). While I had proven to be capable, and I got the support of the bosses, it was still hard pressed for me be allowed to work remotely. There were a lot of bureaucracy which almost made it all fall out in the sand. I even started looking for other companies and I was super clear that I would leave if we didn’t reach an agreement before a certain date.&lt;/p&gt;
&lt;p&gt;In the end we came to an agreement that I would stay with them (we also discussed the possibility of me starting a consultancy business), but I could work from home. Before me moving I had also tried out working remotely during December and working from home one day a week.&lt;/p&gt;
&lt;p&gt;It was very important for me to find a remote job, since there are no on-site jobs for a software developer here. The only other options would be to change my profession or to start my own software company. Neither appealed to me at the time. Veronica is a teacher and she didn’t have any problem getting hired.&lt;/p&gt;
&lt;h1&gt;Working remotely&lt;/h1&gt;
&lt;p&gt;I’ve only been working remotely for a year, so my thoughts on this might very well change. I’m also the &lt;em&gt;only&lt;/em&gt; one working truly remotely, although we do have offices all over the world and we communicate a lot via mail and audio calls.&lt;/p&gt;
&lt;p&gt;These are the most &lt;strong&gt;positive&lt;/strong&gt; things about remote work for me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Fewer interruptions&lt;/p&gt;
&lt;p&gt;One of the things I hate more than anything is when you’re working intensely, achieving a valuable flow-state, and you get interrupted for trivial reasons. My favorite is someone coming to ask if I “saw the email he sent.” There’s no possibility of them coming to disturb me when they’re at least a thousand km away.&lt;/p&gt;
&lt;p&gt;Yes there’s still possible to get disturbed by digital notifications, but they can be managed by turning them off, hiding them or ignoring them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zero commute&lt;/p&gt;
&lt;p&gt;I never realized how much time went to commuting. Even though I &lt;em&gt;only&lt;/em&gt; had 30 min to work, that’s still 1 hour of every day or 5 hours per week almost wasted. Now I have less than a minute from my bedroom to my office.&lt;/p&gt;
&lt;p&gt;Of course it’s still a benefit to go out and take some air before you start to work—but I also have that option. Sometimes I go with my kid to kindergarten which gives me that small physical movement and fresh air that’s so beneficial for you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My own office&lt;/p&gt;
&lt;p&gt;Having my own office is amazing, not only because I can be alone, but because I can do with it whatever I want. For example the standard at work is to have two computer screens, but here I can have as many as I want—I have three.&lt;/p&gt;
&lt;p&gt;There’s no noise in my office, while in Linköping there were always people talking (and sometimes dogs barking!) or people playing loud music. Instead I can fill it with whatever music I want, without having to wear headphones all the time, or just enjoy the silence when I’m trying to solve a difficult problem.&lt;/p&gt;
&lt;p&gt;I can fill my shelves with Lego buildings and I don’t have to organize my desk just because someone else wants me to. Not to mention my &lt;a href=&quot;/blog/2019/03/01/home_office_renovation/&quot;&gt;small home gym&lt;/a&gt; right outside the office.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Freedom&lt;/p&gt;
&lt;p&gt;When you work in an office you can’t really do whatever you want. For example some might be offended if you show up to work with pyjamas pants. (Veronica almost goes nuts if I use sweat pants, let alone pyjamas pants.) Although I’ve never done the classic “work without pants” I have enjoyed working in pyjamas pants :)&lt;/p&gt;
&lt;p&gt;While you might be able to workout continually during the day on-site, it’s mostly relegated to doing some push-ups sometimes or going to the gym during lunch. I can do a few weightlifting reps, work a bit, then do some reps more and spread out my workout during the day. It also doesn’t matter if I get all sweaty—there’s nobody to take offense.&lt;/p&gt;
&lt;p&gt;Finally while it shouldn’t be frowned upon to take a short nap during your break (there’s even a dedicated resting room at the office in Linköping) it can be looked down upon if you do. Well there’s nobody here to judge me if I do take a power-nap or build some Lego during my breaks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And of course there are &lt;strong&gt;negatives&lt;/strong&gt; to remote work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Less social interactions&lt;/p&gt;
&lt;p&gt;Even though I’m definitely an introvert, and don’t really enjoy social events, I really do miss the social aspect of working in an office. I know it’s always being brought up in these “pros/cons of remote work” posts—yet I still didn’t really understand it until I experienced it myself.&lt;/p&gt;
&lt;p&gt;In Linköping I used to play fighting games with a coworker during our afternoon break, something I do miss now. But also the small things like cracking a joke or just nodding to people you pass in the corridor are valuable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Self-control is more difficult&lt;/p&gt;
&lt;p&gt;While I find it easier to find time for focus time, or deep work time, I also find it’s more difficult to have 100% focus on work when working from home. It’s just so easy to be distracted by one of my hobbies or something at the house like the dishes.&lt;/p&gt;
&lt;p&gt;Mostly it’s the less interesting tasks, or less challenging tasks, that I have more trouble focusing on than the hard problems. If I work at the office then I don’t really have much to distract me, other than going to a coworker for a chat, but at home there are simply more possible distractions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Knowledge isolation&lt;/p&gt;
&lt;p&gt;While it doesn’t bother me that much I do feel more isolated now. I don’t really know what’s going on at the office, or with the company at large, or what other people are up to. I assume this is one reason why people say to look for companies where everyone work remotely, not just a few.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s important to consider these points within the context of my work. In lines with the &lt;a href=&quot;https://doist.com/blog/complete-guide-to-deep-work/&quot;&gt;ideas of deep work&lt;/a&gt;, that you should focus on the tasks that provide the most value and prioritizing focus time on them, I have tried to position myself as someone who can focus on the problems at hand with few distractions.&lt;/p&gt;
&lt;p&gt;For example I don’t coordinate people, which requires a lot of interactions and running around trying to get a hold of people. I will of course help people if I can, but if you want my help I do require you to have done some work to try to narrow down the problem. Otherwise it’s easy to spend hours trying to replicate the problem, or even getting their setup up and running, only to find it was a different problem entirely.&lt;/p&gt;
&lt;p&gt;This kind of work, with a big emphasis on focus time, mashes well with my perceived strengths and weaknesses of remote work. I don’t think it would work well if I was a manager, who would fill the day with shallow work (it &lt;em&gt;does not&lt;/em&gt; mean less important work, it’s just a different type of work) and relied more on being “in the know”.&lt;/p&gt;
&lt;p&gt;I’m also not working remotely 100%, I do travel to Linköping about once every second month for a week at a time. Although it’s not so nice to be away from Veronica and Isidor a whole week it absolutely helps offset the lack of social interaction at work. I’m not even sure I would like to work completely remote, unless I could offset it with social activities on my free time.  And of course I do talk to people at work too—I talk daily with the guy I’m working on this project with for example.&lt;/p&gt;
&lt;p&gt;All-in-all I do feel the benefits of working remotely outweigh the negatives for me.&lt;/p&gt;
&lt;h1&gt;The benefits of moving&lt;/h1&gt;
&lt;p&gt;Given the prerequisite of having work, I feel two major benefits of our move:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The cost of living&lt;/p&gt;
&lt;p&gt;The house in the towns of Sweden have risen dramatically the last years, starting around the time we moved to Linköping. But where we live now the house prices are stupid low, so low that people don’t even build new houses because they’re not valuable enough to get a good loan to build them.&lt;/p&gt;
&lt;p&gt;We bought our house for, I kid you not, 1/10th of what a colleague of mine bought a smaller house for in Linköping (a while away from work). With the rising house prices it’s almost worth 15x by now. Granted it’s a much newer and fancier house, but that’s still a lot of money. And it’s not like we bought a shitty house either—it’s older but it’s in good condition.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We live near our parents&lt;/p&gt;
&lt;p&gt;Because we have our 2-year old son Isidor, it’s &lt;em&gt;extremely&lt;/em&gt; helpful to live near our helpful parents. They help us fetch Isidor from kindergarten, take him for walks, babysit him when needed and just generally help us in various ways.&lt;/p&gt;
&lt;p&gt;When talking to other couples who don’t have their parents they always remind me what a luxury this is. They’re probably right.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Veronica also didn’t like the weather in Linköping and prefers the colder climate here in the north and likes the slower tempo of a smaller community. I’m personally not too bothered and I would like it either way.&lt;/p&gt;
&lt;h1&gt;What we’re missing from the city&lt;/h1&gt;
&lt;p&gt;I liked Linköping more than I thought I would. Before moving there I always thought I never wanted to live in a city, yet now I think I might even get comfortable in a larger city. There are a couple of things we miss:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;More activities&lt;/p&gt;
&lt;p&gt;In a city there are more clubs, more workshops, easier to find people to join my weird hobbies and there’s just more things happening. For example I started training Brazilian Jiu-Jitsu in Linköping, but there’s nothing similar near us now. I used to play a lot of Android Netrunner (a collectible card game) and boardgaming, but that’s also much more difficult to organize here.&lt;/p&gt;
&lt;p&gt;For kids there are just tons of sports and other hobbies in a city. When we were little kids either did ice-hockey, football or basketball. Nothing much has changed on that front.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Friends&lt;/p&gt;
&lt;p&gt;As we lived in Linköping for 8 years we had made friends there that we now moved away from. I guess this is just how it is when you move, but it’s still something I miss.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restaurants&lt;/p&gt;
&lt;p&gt;Maybe you could say this is an activity, but it’s worth singling out as both I and Veronica misses the option to go out and eat—we both love food after all. We didn’t do it that often, and we do it much less now when we have kids, but it’s still nice to have the option. Here we have a hamburger place, a pizza joint and a fancier restaurant a little bit outside. Otherwise we’d have to drive at least an hour to find a nice restaurant.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hospitals are far away&lt;/p&gt;
&lt;p&gt;Because of cost savings the hospitals have been centralizing into the big city hospitals. We do have one here, that’s too small to be called a hospital, where you can get help for some things. But if there’s something bigger we need to travel either one or two hours. For example when giving birth we’re looking at a 2 hour trip by car (or 1.5 hour if you’re in a hurry!)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are other things that we’re missing out on, like all the clothes stores downtown or &lt;em&gt;really&lt;/em&gt; fast internet. But those are minors that I really don’t care much about.&lt;/p&gt;
&lt;h1&gt;Do I like it here?&lt;/h1&gt;
&lt;p&gt;Yes, I do like it here. I could imagine myself staying in Linköping, but it made sense for us to move and it still does. So far the pros outweigh the cons, and I don’t expect that to change.&lt;/p&gt;
</content></entry><entry><title>Food vacation in Japan</title><id>http://jonashietala.se/blog/2019/07/18/food_vacation_in_japan/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/07/18/food_vacation_in_japan" rel="alternate"/><published>2019-07-18T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Me and my friend spent 2 weeks in Japan and had a great time. I wasn’t planning on taking a lot of pictures, but I ended up sending a bunch back home as a ways of keeping my family up to date. When I look back most of them are about food… So I’ll turn this into a post about the various foods we ate in Japan!&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/japan-food/onsen-breakfast.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/onsen-breakfast.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/onsen-dinner.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/onsen-dinner.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Breakfast and dinner at an Onsen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Japan has this supposedly famous breakfast, it’s more like a dinner than what we in Sweden call breakfast. And sure enough we got to eat our bellies full. I don’t usually eat breakfast, but this was actually pretty nice. Maybe it was because we slept almost 12 hours after our trip?&lt;/p&gt;
&lt;p&gt;We also had dinner with a lot of different courses (I only took one picture though). It was also very good but I don’t really know what we ate…&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/japan-food/maid.jpg&quot; /&gt;
&lt;figcaption&gt;What I ate at a &lt;a href=&quot;https://en.wikipedia.org/wiki/Maid_caf%C3%A9&quot;&gt;Maid café&lt;/a&gt;. The ketchup is supposed to be &lt;a href=&quot;https://duckduckgo.com/?q=yotsuba+quintuplets&amp;amp;t=ffab&amp;amp;iar=images&amp;amp;iax=images&amp;amp;ia=images&quot;&gt;Yotsuba&lt;/a&gt;, but I don’t see it.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And of course we had to visit a &lt;a href=&quot;https://en.wikipedia.org/wiki/Maid_caf%C3%A9&quot;&gt;Maid café&lt;/a&gt;. The whole experience as extremely weird… Unfortunately the food wasn’t that great either, it was the only time I was disappointed of the food in the whole trip (except the worthless airline food).&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/japan-food/wagyu.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/wagyu.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/wagyu2.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/wagyu2.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Wagyu. Japanese beef.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We ate some kind of local meat—Wagyu—at a fancy restaurant. It was &lt;strong&gt;extremely&lt;/strong&gt; good. We ate a lot of great food during our trip but this was my favorite. Of course it was expensive, but you should still consider it if you ever go to Japan.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/japan-food/grilled.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/grilled.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/grilled2.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/grilled2.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Yakiniku, meat we got to grill ourselves.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My friend was really hyped to go to an all-you-can-eat place where you grill your meat yourself. And for good reason—it was amazing. I love meat, and the meat was great, and I enjoyed the process of grilling the meat. Also a must if you ever go to Japan IMHO.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/japan-food/chabuchabu.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/chabuchabu.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/chabuchabu2.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/chabuchabu2.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Shabu-shabu. A hot pot where we dumped meat and vegetables then fished them out and ate them.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Another similar concept is Shabu-shabu. Instead of grilling the meat you drop it into a pot with boiling water and fish it up after a few seconds. It was also very good, but not as great as Yakiniku.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/japan-food/sushi-assortment2.jpg&quot; /&gt;
&lt;figcaption&gt;Assortment of sushi and sashimi.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Of course we had to eat sushi. I don’t remember how many times, but we ate it several times in different forms. This was the fanciest setup I came across.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/japan-food/meat-ball.jpg&quot; /&gt;
&lt;figcaption&gt;Some kind of meat explosion. It wasn’t done in the middle but we had a small stone we could finish it off with.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/japan-food/puffer1.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/puffer1.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/puffer2.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/puffer2.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/puffer3.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/puffer3.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Different meals with puffer fish.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/japan-food/rice-bowl.jpg&quot; /&gt;
&lt;figcaption&gt;Rice bowls with sashimi on top (don’t know the correct term). We also took some dishes we could grill ourselves.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As you can see we grilled our own food (more or less) several times. I really liked to interact with the food and of course how you can decide yourself how well you want your food grilled.&lt;/p&gt;
&lt;p&gt;And we tried another famous Japanese food: &lt;a href=&quot;https://en.wikipedia.org/wiki/Fugu&quot;&gt;Fugu&lt;/a&gt;—the puffer fish that’s deadly if you don’t prepare it correctly. It was kind of underwhelming to be honest, they weren’t all that tasty.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/japan-food/sticks.jpg&quot; /&gt;
&lt;figcaption&gt;Yakitori. Skewered chicken.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Skewered chicken was also really, really good. My favorite type was absolutely the one with chicken skin. It was &lt;strong&gt;sooo&lt;/strong&gt; good. Unfortunately you could easily eat very many of them…&lt;/p&gt;
&lt;figure class=&quot;flex-33&quot;&gt;
&lt;a href=&quot;/images/japan-food/sushi1.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/sushi1.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/sushi2.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/sushi2.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/japan-food/sushi3.jpg&quot;&gt;&lt;img src=&quot;/images/japan-food/sushi3.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Conveyorbelt sushi.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Another concept I loved was conveyor belt sushi. You have a bunch of plates going around and you can just grab one whenever you want. You can also order specific sushi if you don’t see the ones you like.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/japan-food/sushi-tower.jpg&quot; /&gt;
&lt;figcaption&gt;Conveyor belt sushi can be dangerous. Each plate had about 2 sushi pieces, you can see my tower to the left and my friend’s to the right. I ate 30+ sushi pieces, which is more than double what I normally eat.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Of course I do have a love-hate relationship with it. On one hand it’s great that you can eat as much as you want, and only your favorite pieces, but on the other hand your wallet and stomach will complain if you have poor impulse control—just like me.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/japan-food/random.jpg&quot; /&gt;
&lt;figcaption&gt;Having a screen where you can order drinks or food was quite common.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We ate a bunch more food which I didn’t capture with my camera. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ramen&lt;/li&gt;
&lt;li&gt;Burritos (not Japanese but still very good)&lt;/li&gt;
&lt;li&gt;Some kind of Vietnamese food&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary I’ll conclude the food in Japan was great.&lt;/p&gt;
</content></entry><entry><title>My MCU movie ranking</title><id>http://jonashietala.se/blog/2019/04/25/my_mcu_movie_ranking/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/04/25/my_mcu_movie_ranking" rel="alternate"/><published>2019-04-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I did the &lt;a href=&quot;https://www.reddit.com/r/marvelstudios/comments/a1jmuo/mcu_movie_rewatch_begins_tomorrow/&quot;&gt;MCU Movie Re-Watch&lt;/a&gt; again this year in preparation for Avengers: Endgame. I wasn’t a huge MCU fan before doing the same re-watch for Infinity War, but after that I became one.&lt;/p&gt;
&lt;p&gt;For fun I tried to rank the movies as I saw them, this is some sort of accounting my rankings and how they changed compared to last year. I did see Endgame yesterday, but I won’t be spoiling it here (other than I thought it was very good).&lt;/p&gt;
&lt;h1&gt;S-rank&lt;/h1&gt;
&lt;p&gt;The creame of the crop. The films I never get tired of.&lt;/p&gt;
&lt;table class=&quot;movie-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Movie&lt;/th&gt;&lt;th&gt;Rank this year&lt;/th&gt;&lt;th&gt;Rank last year&lt;/th&gt;&lt;th&gt;change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Avengers: Endgame&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Guardians of the Galaxy&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;+3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Avengers: Infinity War&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;+1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Iron Man&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;-3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Captain America: The Winter Soldier&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;-2&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Yes I’m ranking Endgame as #1. It might very well be me coming from it fresh and I haven’t settled on it yet.&lt;/p&gt;
&lt;p&gt;Guardians of the Galaxy jumped up for a very simple reason: It’s the movie with the greatest re-watch value. I just love everything about it.&lt;/p&gt;
&lt;p&gt;Iron Man and The Winter Solder went down a few pegs, but they’re still &lt;strong&gt;very&lt;/strong&gt; good movies. They have quite a different feeling than the others.&lt;/p&gt;
&lt;h1&gt;A-rank&lt;/h1&gt;
&lt;p&gt;Also very good movies, but not in the same league as the above.&lt;/p&gt;
&lt;table class=&quot;movie-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Movie&lt;/th&gt;&lt;th&gt;Rank this year&lt;/th&gt;&lt;th&gt;Rank last year&lt;/th&gt;&lt;th&gt;change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Ant-Man and the Wasp&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Spider-Man: Homecoming&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;+3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Thor: Ragnarok&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;+4&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Doctor Strange&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;-3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Ant-Man&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;-3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Black Panther&lt;/td&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;-9&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;These are all pretty close to me and could easily be rearranged.&lt;/p&gt;
&lt;p&gt;Although the Ant-Man movies don’t perform very well on the box office compared to the other MCU movies I absolutely love them. They’re just so &lt;em&gt;fun&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Both Thor: Ragnarok and Spider-Man have a very high re-watch value. In contrast Black Panther didn’t hold up well compared to when I saw it at the cinema last year. The anticipation hype probably made me appreciate it more than usual.&lt;/p&gt;
&lt;p&gt;I do love Doctor Strange, he’s probably my favorite hero together with Iron Man. When looking at it now it feels weird it’s only ranked 9th.&lt;/p&gt;
&lt;h1&gt;Rank B&lt;/h1&gt;
&lt;p&gt;Good movies which are only missing something a little extra.&lt;/p&gt;
&lt;table class=&quot;movie-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Movie&lt;/th&gt;&lt;th&gt;Rank this year&lt;/th&gt;&lt;th&gt;Rank last year&lt;/th&gt;&lt;th&gt;change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Captain Marvel&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Guardians of the Galaxy 2&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;-4&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Captain America: Civil War&lt;/td&gt;&lt;td&gt;14&lt;/td&gt;&lt;td&gt;14&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;The Avengers: Age of Ultron&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;-2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;The Avengers&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;-5&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Captain America: The First Avenger&lt;/td&gt;&lt;td&gt;17&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;-9&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;GotG 2 is in a bit of a weird spot. It depends heavily on your mood when you’re watching it: it can be amazing or it can fall a little flat. It does have some fantastic moments.&lt;/p&gt;
&lt;p&gt;I also didn’t know how to rank Captain Marvel. Don’t get me wrong—it was a good movie. But I didn’t get the “oh my god nerdgasm” feeling (well I did get it a little). When I re-watch it it’s ranking will probably change.&lt;/p&gt;
&lt;p&gt;When I look at the ranking lists of others the duo Civial War and The Avengers are often very highly rated. But I personally don’t quite get the hype, they’re good but not very good.&lt;/p&gt;
&lt;p&gt;The First Avenger has some cool moments but I honestly zoned out a bit at the end. Not a good sign.&lt;/p&gt;
&lt;h1&gt;Rank C&lt;/h1&gt;
&lt;p&gt;Okay movies.&lt;/p&gt;
&lt;table class=&quot;movie-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Movie&lt;/th&gt;&lt;th&gt;Rank this year&lt;/th&gt;&lt;th&gt;Rank last year&lt;/th&gt;&lt;th&gt;change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Iron Man 3&lt;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;-3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Iron Man 2&lt;/td&gt;&lt;td&gt;19&lt;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;td&gt;-1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Thor&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;-4&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;It’s a little strange. I love Iron Man the character but there are problems with his 2nd and 3rd movies. Everything including Iron Man—and of course Justin Hammer—is great but the villains are lackluster and there’s just something missing.&lt;/p&gt;
&lt;p&gt;Similarly Thor didn’t age very well.&lt;/p&gt;
&lt;h1&gt;Rank D&lt;/h1&gt;
&lt;p&gt;Watchable but not something I’d choose unless for a special occasion.&lt;/p&gt;
&lt;table class=&quot;movie-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Movie&lt;/th&gt;&lt;th&gt;Rank this year&lt;/th&gt;&lt;th&gt;Rank last year&lt;/th&gt;&lt;th&gt;change&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;The Incredible Hulk&lt;/td&gt;&lt;td&gt;21&lt;/td&gt;&lt;td&gt;19&lt;/td&gt;&lt;td&gt;-2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Thor 2: The Dark World&lt;/td&gt;&lt;td&gt;22&lt;/td&gt;&lt;td&gt;17&lt;/td&gt;&lt;td&gt;-5&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;I really don’t think they’re bad movies. But there’s nothing really noteworthy in them either. They’re mostly boring.&lt;/p&gt;
&lt;h1&gt;Observations&lt;/h1&gt;
&lt;p&gt;It’s natural that movies with high re-watch value tend to rise in the rankings. But it got me thinking—do good movies have high re-watch value? Can you identify good movies by looking at how re-watchable they are?&lt;/p&gt;
&lt;p&gt;GotG, Thor: Ragnarok and Spider-Man surprised me this time of how much more I enjoyed to see them again compared to the other films. Maybe that’s a good indication of their quality?&lt;/p&gt;
&lt;p&gt;Another thing that stands out is how much your mood and the watching experience contributes. For example I was ecstatic after having seen Black Panther, Infinity War and Endgame at the cinema. That will of course have a huge effects on their rankings. In contrast I was kind of tired and zoned out while watching some of the other movies, like The First Avenger.&lt;/p&gt;
&lt;p&gt;Lastly I’ll note that the MCU really embodies the phrase “the whole is greater than the sum of its parts”. While they might not be the best individual movies I’ve ever seen, the whole experience of 20 interconnected movies really elevates everything a notch or two.&lt;/p&gt;
&lt;p&gt;I’ve never been as hyped for a movie as I was for Infinity War and Endgame. It was almost ridiculous and I never thought they could live up to my expectations. But they exceeded it.&lt;/p&gt;
&lt;p&gt;Can’t wait for my next re-watch.&lt;/p&gt;
</content></entry><entry><title>I&apos;m writing a book: Why Cryptocurrencies?</title><id>http://jonashietala.se/blog/2019/04/17/im_writing_a_book_why_cryptocurrencies/index.html</id><updated>2024-04-02T04:12:58+00:00</updated><link href="https://www.jonashietala.se/blog/2019/04/17/im_writing_a_book_why_cryptocurrencies" rel="alternate"/><published>2019-04-17T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I decided to write a book. It’s called “Why Cryptocurrencies?” and I will be uploading chapters as I complete them. It’s available to &lt;a href=&quot;https://whycryptocurrencies.com/&quot;&gt;read online for free&lt;/a&gt;. I’ve only uploaded the introductory parts but I’ve got a bunch more planned.&lt;/p&gt;
&lt;p&gt;Why write a book you ask? Well, why not?&lt;/p&gt;
&lt;p&gt;I wanted to have a side project I can work on. It’s something I can use to improve my writing, even more than on this blog. And it’s been on my bucket list forever. Now just felt like a good time to try my hand at it.&lt;/p&gt;
&lt;p&gt;Cryptocurrencies is such a misunderstood topic where everyone seem to have an opinion, but the focus seem to only be on the speculative side. Unless of course they’re dismissed outright. All without an understanding of what they are and what they can do.&lt;/p&gt;
&lt;p&gt;This is what the book is about. To explain what they are and how they can be useful. Time will tell if I manage to contribute anything to the subject or not.&lt;/p&gt;
</content></entry><entry><title>Picking up rust by writing a QR code generator</title><id>http://jonashietala.se/blog/2019/04/17/picking_up_rust_by_writing_a_qr_code_generator/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/04/17/picking_up_rust_by_writing_a_qr_code_generator" rel="alternate"/><published>2019-04-17T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I wanted to pick up &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;rust&lt;/a&gt; again after having used it many years ago. After around 5 years or so I didn’t really know where to start?&lt;/p&gt;
&lt;h1&gt;Approaches to picking up a language&lt;/h1&gt;
&lt;p&gt;When learning, or as in this case re-learning, a programming language there are different approaches. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read book(s).&lt;/li&gt;
&lt;li&gt;Solve different kinds of programming puzzles.&lt;/li&gt;
&lt;li&gt;Follow a tutorial while following along with your own code.&lt;/li&gt;
&lt;li&gt;Make a small game.&lt;/li&gt;
&lt;li&gt;Using it in a real project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve read a lot of programming books and in general it’s a very good tool to learn new things. For rust you could for example read &lt;a href=&quot;https://doc.rust-lang.org/stable/book/title-page.html&quot;&gt;The Rust Programmaing Language&lt;/a&gt;, which is a pretty good introduction.&lt;/p&gt;
&lt;p&gt;During my university time I did a little competitive programming, so you’d think I’d love the idea of solving programming puzzles. For example via &lt;a href=&quot;https://www.forrestthewoods.com/blog/learning-rust-via-advent-of-code/&quot;&gt;Advent of Code&lt;/a&gt;, &lt;a href=&quot;https://projecteuler.net/&quot;&gt;Project Euler&lt;/a&gt; or doing &lt;a href=&quot;https://github.com/gamontal/awesome-katas&quot;&gt;katas&lt;/a&gt;. But truth be told—I’m not that into such puzzles. I prefer making “real” projects that does something useful for me.&lt;/p&gt;
&lt;aside&gt;As a sidenote katas in classical martial arts is a waste of time if you want to get good at fighting or self defense. You need to train against resistance in as realistic scenarios as possible, like you do when sparring. Coding katas are more useful but I personally don’t enjoy them.&lt;/aside&gt;
&lt;p&gt;Following a tutorial, like the excellent &lt;a href=&quot;https://os.phil-opp.com/&quot;&gt;writing an OS in Rust&lt;/a&gt;, can be amazingly useful. Both for learning a language but mostly for learning about a specific domain—like learning about operating systems.&lt;/p&gt;
&lt;p&gt;Personally though after programming for several years, and having used so many languages, I prefer to just pick up a language and try to create something in it.&lt;/p&gt;
&lt;h1&gt;A QR code generator&lt;/h1&gt;
&lt;p&gt;By chance I found a thorough &lt;a href=&quot;https://www.thonky.com/qr-code-tutorial/&quot;&gt;QR code tutorial&lt;/a&gt; and it got me thinking, is it a good starter project?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s big enough to let me explore many of rust’s features.&lt;/li&gt;
&lt;li&gt;It’s limited in scope.&lt;/li&gt;
&lt;li&gt;I get to learn how QR codes work, which is something I’ve been curious about.&lt;/li&gt;
&lt;li&gt;There’s a tutorial, so in theory I just have to implement it.&lt;/li&gt;
&lt;li&gt;There are tons of reference implementations I can compare to if I get stuck.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Seems pretty good! So &lt;a href=&quot;https://github.com/treeman/rqr&quot;&gt;I made one&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is how you can produce a QR code in a string representation:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;keyword other rust&quot;&gt;crate&lt;/span&gt; rqr&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;rqr&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;Qr&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; StringRenderer&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; qr &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Qr&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;HELLO WORLD&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;StringRenderer&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;qr&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or generate an svg:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;keyword other rust&quot;&gt;crate&lt;/span&gt; rqr&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;rqr&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;Qr&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; SvgRenderer&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Color&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; ECLevel&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; qr &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Qr&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;with_ecl&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;HELLO WORLD&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;ECLevel&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Q&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;SvgRenderer&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;light_module&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;Color&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;229&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;189&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;227&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;dark_module&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;Color&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;119&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;dimensions&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        .&lt;span class=&quot;support function rust&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;qr&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s also a simple cli for the above tasks:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;&gt; cargo run --features cli -- &quot;HELLO WORLD&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██████████████        ██    ██████████████        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██          ██  ████    ██  ██          ██        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ██████  ██    ██  ████  ██  ██████  ██        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ██████  ██  ██████████  ██  ██████  ██        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ██████  ██  ████  ██    ██  ██████  ██        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██          ██    ██    ██  ██          ██        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██████████████  ██  ██  ██  ██████████████        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        ████  ████                        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;          ██  ████████  ████    ██████  ████  ██          
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ████████  ██        ████████  ██████          
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            ██  ██  ████      ██    ████                  
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ████  ██      ██  ████      ████              
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ████  ████████████████  ██████  ██████████        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        ██      ██    ██  ██              
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██████████████    ████    ████    ████████        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██          ██  ██  ██    ██    ██  ██████        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ██████  ██  ████  ██    ██      ██████        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ██████  ██  ██  ██████      ██  ██            
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██  ██████  ██    ██        ██        ████        
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██          ██  ██████    ██████    ████          
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ██████████████    ██  ██              ██          
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can customize the svg output there as well:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;&gt; cargo run --features cli -- &quot;HELLO WORLD&quot; -t svg --bg &apos;#e5bde3&apos; \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    --fg &apos;#700&apos; --width 200 &gt; hello_world.svg
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;
&lt;img src=&quot;https://raw.githubusercontent.com/treeman/rqr/master/src/test/hello_world.svg?sanitize=true&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.rs/rqr&quot;&gt;documentation&lt;/a&gt; and overall code quality should be fairly good but as this was just a learning project I don’t plan on extending it with new features.&lt;/p&gt;
</content></entry><entry><title>Easy setup of a static site on Amazon S3 with SSL</title><id>http://jonashietala.se/blog/2019/04/03/easy-setup-of-a-static-site-on-amazon-s3-with-ssl/index.html</id><updated>2026-04-27T11:10:32+00:00</updated><link href="https://www.jonashietala.se/blog/2019/04/03/easy-setup-of-a-static-site-on-amazon-s3-with-ssl" rel="alternate"/><published>2019-04-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been hosting my site on Amazon S3 for a while now but I never activated SSL for it. I just never got around to it, probably the usual procrastination.&lt;/p&gt;
&lt;p&gt;When I had to setup a new site for another project I chose to host on Amazon as well. Although there are many other free options, why switch when it’s working? This time I activated SSL as well—and documented it. It’s all quite easy.&lt;/p&gt;
&lt;h1&gt;Host a static site on S3&lt;/h1&gt;
&lt;p&gt;First we need to &lt;a href=&quot;https://console.aws.amazon.com/s3/home&quot;&gt;create a bucket on S3&lt;/a&gt;, it’s straightforward. When you’re done activate static website hosting:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/s3_setup/static_website.png&quot; /&gt;
&lt;figcaption&gt;Make sure to add the Index document.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I use a &lt;a href=&quot;https://codeberg.org/treeman/jonashietala/src/branch/master/sync&quot;&gt;crappy script&lt;/a&gt; to sync my site, but there are many other tools. You could also upload files via the &lt;a href=&quot;https://console.aws.amazon.com/s3/home&quot;&gt;S3 console&lt;/a&gt; to get started. When you’ve uploaded a site you can visit the Endpoint to confirm that it works. For example:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://whycryptocurrencies.com.s3-website.eu-north-1.amazonaws.com/&quot;&gt;http://whycryptocurrencies.com.s3-website.eu-north-1.amazonaws.com/&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Custom domain&lt;/h1&gt;
&lt;p&gt;This is a really crappy url, so let’s use our custom domain. Add a CNAME record pointing to the Endpoint. It might be a good idea to add a redirect from www to @ (or vice versa). This is how it might look on &lt;a href=&quot;https://www.namecheap.com/&quot;&gt;namecheap&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/s3_setup/s3_domains.png&quot; /&gt;
&lt;figcaption&gt;Here I redirect from www to @, but it really doesn’t matter which way.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;After waiting for the settings to update, which can be annoying for someone as impatient as myself, you can then visit the site from your domain.&lt;/p&gt;
&lt;p&gt;For example &lt;a href=&quot;http://whycryptocurrencies.com&quot;&gt;http://whycryptocurrencies.com&lt;/a&gt;, but without SSL support.&lt;/p&gt;
&lt;h1&gt;CloudFront&lt;/h1&gt;
&lt;p&gt;To enable SSL we need a CloudFront distribution. Don’t worry, it’s also free and might come with other benefits.&lt;/p&gt;
&lt;p&gt;Start by &lt;a href=&quot;https://console.aws.amazon.com/cloudfront/home&quot;&gt;creating a distribution&lt;/a&gt;. Make sure to create a web distribution and go through these options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Origin domain name
Select your S3 bucket&lt;/li&gt;
&lt;li&gt;Redirect HTTP to HTTPS&lt;/li&gt;
&lt;li&gt;Compress objects automatically&lt;/li&gt;
&lt;li&gt;Alternative domain names, input your domain. Like &lt;code&gt;whycryptocurrencies.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use the default cloudfront SSL certificate for now, we’ll change this later&lt;/li&gt;
&lt;li&gt;Default root object: &lt;code&gt;index.html&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When it’s deployed, wait for it, we can test access by visiting the address under Domain Name. For me that was &lt;a href=&quot;http://d29jm6e61zesqa.cloudfront.net&quot;&gt;http://d29jm6e61zesqa.cloudfront.net&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You will get redirected to a https address but we need to update our custom domain to point to the cloudfront address. Like so:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/s3_setup/namecheap_cloudfront.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;When the settings have updated and we visit our domain we will get a “Insecure Connection” warning because the SSL certificate we’re using is only valid for cloudfront endpoints, not our own domain. Fixing this is the final step.&lt;/p&gt;
&lt;h1&gt;Enable SSL via AWS Certificate Manager&lt;/h1&gt;
&lt;p&gt;At first I thought I had to use &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;let’s encrypt&lt;/a&gt; to create a SSL certificate. They are great but all guides I could see involved a bunch of command line work, which you had to do regularly to renew your certificate. But there’s an easier way directly in AWS, which is also free.&lt;/p&gt;
&lt;p&gt;If we go back to our CloudFront distribution end Edit the General settings we’ll see the SSL Certificate settings:&lt;/p&gt;
&lt;p&gt;Click on the “Request or Import a Certificate with ACM” to get to the &lt;a href=&quot;https://console.aws.amazon.com/acm/home&quot;&gt;AWS Certificate Manager&lt;/a&gt; (or just lick the link).&lt;/p&gt;
&lt;p&gt;Make sure to input both your domain and a subaddress wildcard as domain names. I used &lt;code&gt;whycryptocurrencies.com&lt;/code&gt; and &lt;code&gt;*.whycryptocurrencies.com&lt;/code&gt; for example.&lt;/p&gt;
&lt;p&gt;It doesn’t matter if you use DNS or email validation.  If you choose DNS validation you’ll be asked to add a new subdomain with a CNAME value. Like so:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/s3_setup/DNS_validation.png&quot; /&gt;
&lt;figcaption&gt;_c20fab3bbd32430576cfdcdd43b090d1 is the subdomain with the value _7e714a15b4afabada0784649c5eac502.hkvuiqjoua.acm-validations.aws.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;… And we’ll need to wait again until it’s validated.&lt;/p&gt;
&lt;p&gt;Finally we just need to tell CloudFront to use the new certificate. Go back and edit the General settings choose the Custom SSL Certificate option:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/s3_setup/cert.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;And we should be done! Now &lt;a href=&quot;https://whycryptocurrencies.com&quot;&gt;https://whycryptocurrencies.com&lt;/a&gt; should give a valid cert and http should redirect to https.&lt;/p&gt;
&lt;p&gt;Remember how I said we need patience? When I did all these steps firefox kept warning me about a bad SSL cert and I couldn’t for the life of me see where I went wrong. After a while I gave up and went to bed, but the next day it all magically worked. Turns out I didn’t have enough patience.&lt;/p&gt;
&lt;p&gt;You know some say sleeping solves your problems? In this case it literally did.&lt;/p&gt;
</content></entry><entry><title>Default audio card in linux</title><id>http://jonashietala.se/blog/2019/03/16/default_audio_card_in_linux/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/03/16/default_audio_card_in_linux" rel="alternate"/><published>2019-03-16T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;There are a bunch of posts about making your audio work by default in Linux but none that just worked for me.&lt;/p&gt;
&lt;p&gt;I had three separate problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Getting sound&lt;/li&gt;
&lt;li&gt;Playing sound from multiple sources at the same time&lt;/li&gt;
&lt;li&gt;Audio card getting different numbers on reboot&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Getting sound&lt;/h1&gt;
&lt;p&gt;Here I followed &lt;a href=&quot;http://www.troubleshooters.com/linux/void/voidtips.htm#audio&quot;&gt;this excellent guide&lt;/a&gt;, here’s a summary:&lt;/p&gt;
&lt;p&gt;Firstly identify card number and device number:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;~&gt; aplay -l
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;**** List of PLAYBACK Hardware Devices ****
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 0: Audio [TEAC AI-101 Audio], device 0: USB Audio [USB Audio]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 0/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 1: Generic_1 [HD-Audio Generic], device 0: ALC1220 Analog [ALC1220 Analog]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 1: Generic_1 [HD-Audio Generic], device 1: ALC1220 Digital [ALC1220 Digital]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 2: Generic [HD-Audio Generic], device 3: HDMI 0 [HDMI 0]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 2: Generic [HD-Audio Generic], device 7: HDMI 1 [HDMI 1]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 2: Generic [HD-Audio Generic], device 8: HDMI 2 [HDMI 2]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 2: Generic [HD-Audio Generic], device 9: HDMI 3 [HDMI 3]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 2: Generic [HD-Audio Generic], device 10: HDMI 4 [HDMI 4]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;card 2: Generic [HD-Audio Generic], device 11: HDMI 5 [HDMI 5]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevices: 1/1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Subdevice #0: subdevice #0
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But to test with &lt;code&gt;speaker-test&lt;/code&gt; we need info from the &lt;code&gt;aplay -L&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;~&gt; aplay -L
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;null
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Discard all samples (playback) or generate zero samples (capture)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;sysdefault:CARD=Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Default Audio Device
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;front:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Front speakers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;surround21:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    2.1 Surround output to Front and Subwoofer speakers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;surround40:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    4.0 Surround output to Front and Rear speakers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;surround41:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    4.1 Surround output to Front, Rear and Subwoofer speakers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;surround50:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    5.0 Surround output to Front, Center and Rear speakers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;surround51:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    5.1 Surround output to Front, Center, Rear and Subwoofer speakers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;surround71:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    7.1 Surround output to Front, Center, Side, Rear and Woofer speakers
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;iec958:CARD=Audio,DEV=0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    TEAC AI-101 Audio, USB Audio
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    IEC958 (S/PDIF) Digital Audio Output
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can test:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;speaker-test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;t&lt;/span&gt; sin&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;f&lt;/span&gt; 800&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;Dfront&lt;/span&gt;:Audio&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;c2        &lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; No sound for me&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;speaker-test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;t&lt;/span&gt; sin&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;f&lt;/span&gt; 800&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;Dsysdefault&lt;/span&gt;:Audio&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;c2   &lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; This works!&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we know that &lt;code&gt;card 0: Audio [TEAC AI-101 Audio], device 0&lt;/code&gt; is the card we want. Try this in &lt;code&gt;~/.asoundrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;pcm.!default {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  type plug
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  slave {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    pcm &quot;hw:0,0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ctl.!default {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  type hw
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  card 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we instead have for example &lt;code&gt;card 1, device 2&lt;/code&gt; then we use &lt;code&gt;hw:1,2&lt;/code&gt; and &lt;code&gt;card 1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Do &lt;code&gt;speaker-test -t sin -f 800&lt;/code&gt; to test or something else like youtube.&lt;/p&gt;
&lt;h1&gt;Sound from multiple sources&lt;/h1&gt;
&lt;p&gt;Directly from &lt;a href=&quot;http://www.troubleshooters.com/linux/void/voidtips.htm#audio&quot;&gt;the same guide&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;pcm.!default {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    type plug
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    slave.pcm &quot;dmixer&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pcm.dmixer  {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    type dmix
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ipc_key 1024
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    slave {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        pcm &quot;hw:0,0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        period_time 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        period_size 1024
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        buffer_size 4096
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        rate 44100
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    bindings {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        0 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        1 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ctl.dmixer {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    type hw
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    card 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure to use your card and device numbers.&lt;/p&gt;
&lt;h1&gt;Different card numbers after reboot&lt;/h1&gt;
&lt;p&gt;After reboot the card number changed, it changed between 0, 1 and 2.&lt;/p&gt;
&lt;p&gt;There were various suggestions online but most didn’t work. I found one suggestion somewhere that said I could just use the card name. I randomly tried something that worked!&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;card 0: Audio [TEAC AI-101 Audio], device 0: USB Audio [USB Audio]
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The name of the card is “Audio” and the &lt;code&gt;~/.asoundrc&lt;/code&gt; becomes:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;pcm.!default {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    type plug
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    slave.pcm &quot;dmixer&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pcm.dmixer {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    type dmix
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ipc_key 1024
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    slave {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        pcm {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            type hw
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            card &quot;Audio&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            device 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        period_time 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        period_size 1024
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        buffer_size 4096
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        rate 44100
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    bindings {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        0 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        1 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ctl.dmixer {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    type hw
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    card &quot;Audio&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Much simpler than messing around with udev to get the card to always occupy the same card number, especially since I often turn on and off the amplifier.&lt;/p&gt;
</content></entry><entry><title>The ASIC pit of despair</title><id>http://jonashietala.se/blog/2019/03/13/the_asic_pit_of_despair/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/03/13/the_asic_pit_of_despair" rel="alternate"/><published>2019-03-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Monero has once again &lt;a href=&quot;https://www.getmonero.org/2018/02/11/PoW-change-and-key-reuse.html&quot;&gt;changed the POW&lt;/a&gt; to brick ASICs following confirmation that &lt;a href=&quot;https://medium.com/@MoneroCrusher/analysis-more-than-85-of-the-current-monero-hashrate-is-asics-and-each-machine-is-doing-128-kh-s-f39e3dca7d78&quot;&gt;85% of Monero’s hashrate were ASICs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Recurring hard forks to brick ASICs is a very dangerous game and what better to illustrate this than with an xkcd-style plot?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/monero-asics-fork.svg&quot; title=&quot;The ASIC pit of despair&quot; width=&quot;100%&quot; /&gt;
&lt;figcaption&gt;You’re safe on the edges but how do you bridge the gap?&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Tufte style sidenotes and marginnotes in Pollen</title><id>http://jonashietala.se/blog/2019/03/04/pollen_sidenotes/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/03/04/pollen_sidenotes" rel="alternate"/><published>2019-03-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;When evaluating Pollen &lt;a href=&quot;/blog/2019/03/03/first_impressions_of_pollen/&quot; title=&quot;First impressions of Pollen&quot;&gt;I complained&lt;/a&gt; about markdown/pandoc’s lack of sidenote handling. I have solved it for Pollen but felt it deserved it’s own post.&lt;/p&gt;
&lt;p&gt;A caveat: I generated &lt;a href=&quot;https://edwardtufte.github.io/tufte-css/&quot; title=&quot;Tufte CSS&quot;&gt;Tufte CSS&lt;/a&gt; style sidenotes and marginnotes which made it more complex than if I had simply generated “standard” sidenotes. If you want to adapt this yourself I’m sure you can simplify the code to fit your needs.&lt;/p&gt;
&lt;p&gt;So in Pollen markup I want to be able to write this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;Lisp is a pretty nice &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;sn&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;cult&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt; language.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;ndef&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;cult&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Some may say it&amp;#39;s the language to rule them all.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To generate this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;Lisp is a pretty nice
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline form html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline form html&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;cult&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;margin-toggle sidenote-number&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline form html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline form html&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline form html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline form html&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;checkbox&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;entity other attribute-name id html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta toc-list id html&quot;&gt;cult&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;       &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;margin-toggle&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;sidenote&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Some may say it&amp;#39;s the language to rule them all.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;language.
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The order of &lt;code&gt;◊sn&lt;/code&gt; and &lt;code&gt;◊ndef&lt;/code&gt; shouldn’t matter.&lt;/p&gt;
&lt;p&gt;By having the sidenote span right in the middle of the text it allows us to &lt;a href=&quot;https://stackoverflow.com/questions/11023816/toggle-divs-without-using-javascript&quot; title=&quot;Toggle divs without using javascript&quot;&gt;toggle it without javascript&lt;/a&gt;. This appeals to me as a heavy noscript user but it has a significant drawback: you cannot have block level tags like &lt;code&gt;div&lt;/code&gt; or &lt;code&gt;p&lt;/code&gt; inside a &lt;code&gt;span&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You also cannot use an &lt;code&gt;aside&lt;/code&gt; instead of a &lt;code&gt;span&lt;/code&gt; directly here as you cannot have it inside a paragraph tag.&lt;/p&gt;
&lt;p&gt;Tufte has both sidenotes and marginnotes which we can implement in a general way. This is the markup:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;This has a sidenote with numbers.&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;sn&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;note&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;This has a marginnote without numbers.&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;mn&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;note&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;ndef&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;note&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    The note itself
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These are the Pollen tags with their markup difference:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;mn&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;note-ref&lt;/span&gt; &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:label-class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;margin-toggle&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:label-content&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;⊕&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:span-class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;marginnote&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;sn&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;note-ref&lt;/span&gt; &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:label-class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;margin-toggle sidenote-number&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:label-content&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:span-class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;sidenote&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll get to the &lt;code&gt;note-ref&lt;/code&gt; definition in a little bit.&lt;/p&gt;
&lt;p&gt;We can use the same markup for sidenote and marginnote content. The idea is to store the content in a map and look it up and insert it into the markup later.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; The note ref -&amp;gt; definition map
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;note-defs&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;make-hash&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; The tag
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;ndef&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt; . &lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;nd-~a&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;string-&amp;gt;symbol&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;hash-set!&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;note-defs&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Simple enough right? If we want to apply post-processing, like adding paragraphs, we need to do some more work. Especially since we cannot have &lt;code&gt;p&lt;/code&gt; tags inside the &lt;code&gt;span&lt;/code&gt;! I solved this by instead wrapping paragraphs with a span I style like paragraphs. This is the actual code:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;ndef&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt; . &lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;nd-~a&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;string-&amp;gt;symbol&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; Because p doesn&amp;#39;t allow block elements
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; and span doesn&amp;#39;t allow p elements
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; use a special span .snp element to emulate paragraphs.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; This is workaround is required as we want to inject a whole sidenote
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; inline to use the checkbox css toggling to avoid javascript.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;wrap&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;list&lt;/span&gt;* &amp;#39;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt; &amp;#39;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;snp&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;content&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;decode-elements&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:txexpr-elements-proc&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;decode-paragraphs&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                     &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:string-proc&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;string-proc&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;hash-set!&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;note-defs&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;code&gt;string-proc&lt;/code&gt; can contain smart quotes expansion or whatever extra decoding you want to use.&lt;/p&gt;
&lt;p&gt;Now to another problem: we want to have refs before defs and vice versa. This means we might parse the references before we’ve registered the definitions. We can solve this by making a decode pass in the root tag and marking refs with a special symbol which we replace. This can be made very general:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; Register symbols which gets inline replaced
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; by function return values.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;replacements&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;make-hash&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;register-replacement&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;sym&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;hash-set!&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;replacements&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;sym&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;replace-stubs&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;hash-ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;replacements&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;constant character lisp&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;f&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is used like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;register-replacement&lt;/span&gt; &amp;#39;&lt;span class=&quot;variable other pollen&quot;&gt;sym-to-replace&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;REPLACED&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;root&lt;/span&gt; . &lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;decode-elements&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:entity-proc&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;replace-stubs&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;root&lt;/code&gt; in Pollen allows you to transform the whole document.&lt;/p&gt;
&lt;p&gt;And now we can get back to our reference tag:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;note-ref&lt;/span&gt; &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:label-class&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;label-class&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                  &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:label-content&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;label-content&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                  &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:span-class&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;span-class&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                  &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;nd-~a&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref-in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;string-&amp;gt;symbol&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;replace&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;hash-ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;note-defs&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;constant character lisp&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;missing ref &amp;#39;~s&amp;#39;&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;label-class&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;for&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;label-content&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;margin-toggle&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;checkbox&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;span-class&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,@&lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;register-replacement&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;variable other pollen&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’s basically just registering a replacement function which returns the markup:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;label-class&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;for&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;label-content&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;margin-toggle&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;checkbox&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;span-class&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,@&lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;invalid illegal stray-bracket-end pollen&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Are we done? Almost. This would create markup wrapped in a span, like:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;meta tag inline form html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline form html&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;cult&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;margin-toggle sidenote-number&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;meta tag inline form html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline form html&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;meta tag inline form html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline form html&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;checkbox&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;entity other attribute-name id html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta toc-list id html&quot;&gt;cult&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;margin-toggle&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;sidenote&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         Some may say it&amp;#39;s the language to rule them all.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The replacement function can only return a single element so we had to wrap it in something. In this particular case it’s not a big deal but it is indeed a general limitation of Pollen tags. Is it something we can get around?&lt;/p&gt;
&lt;p&gt;Yes it is. We can add a special symbol in the markup:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;splice-me&lt;/span&gt; &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt; &amp;lt;- instead of span
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;label-class&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;for&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;label-content&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;margin-toggle&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;checkbox&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; ,&lt;span class=&quot;variable other pollen&quot;&gt;span-class&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; ,@&lt;span class=&quot;variable other pollen&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;invalid illegal stray-bracket-end pollen&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then do an extra post process step to replace it with it’s content, inline:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; A splicing tag to support returning multiple inline
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; values. So &amp;#39;((splice-me &amp;quot;a&amp;quot; &amp;quot;b&amp;quot;)) becomes &amp;#39;(&amp;quot;a&amp;quot; &amp;quot;b&amp;quot;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;splice-me?&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    [&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;cons&lt;/span&gt; &amp;#39;&lt;span class=&quot;variable other pollen&quot;&gt;splice-me&lt;/span&gt; _&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant character lisp&quot;&gt;#t&lt;/span&gt;]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    [&lt;span class=&quot;keyword control pollen&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;constant character lisp&quot;&gt;#f&lt;/span&gt;]&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; Expand &amp;#39;(splice-me ...) into surrounding list
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;expand-splices&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;list?&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;              &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;splice-me?&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;expand-splices&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function pollen&quot;&gt;cdr&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;expand-splices&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;           &amp;#39;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;           &lt;span class=&quot;variable other pollen&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other pollen&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;root&lt;/span&gt; . &lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;decode-elements&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;args&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable named-arg pollen&quot;&gt;#:entity-proc&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;replace-stubs&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;comment line pollen&quot;&gt;&lt;span class=&quot;punctuation definition comment pollen&quot;&gt;;&lt;/span&gt;; Expand splices afterwards
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;txexpr&lt;/span&gt; &amp;#39;&lt;span class=&quot;variable other pollen&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;empty&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;expand-splices&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;decoded&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to do it after &lt;code&gt;decode-elements&lt;/code&gt; since it doesn’t support such a transformation.&lt;/p&gt;
&lt;p&gt;And we’re done! It wasn’t very straightforward to implement Tufte style notes but with Pollen you do get the ability to do it.&lt;/p&gt;
</content></entry><entry><title>First impressions of Pollen</title><id>http://jonashietala.se/blog/2019/03/03/first_impressions_of_pollen/index.html</id><updated>2024-06-27T07:48:20+00:00</updated><link href="https://www.jonashietala.se/blog/2019/03/03/first_impressions_of_pollen" rel="alternate"/><published>2019-03-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After having consumed &lt;a href=&quot;https://practicaltypography.com/&quot; title=&quot;Practical Typography&quot;&gt;Practical Typography&lt;/a&gt; I took a look at the library he wrote to create books for the web called &lt;a href=&quot;https://docs.racket-lang.org/pollen/&quot; title=&quot;Pollen site generator&quot;&gt;Pollen&lt;/a&gt; written in &lt;a href=&quot;https://racket-lang.org/&quot; title=&quot;Racket programming language&quot;&gt;Racket&lt;/a&gt;. I’ve only used it a little but I feel I can give my first impressions of it.&lt;/p&gt;
&lt;h1&gt;What I like&lt;/h1&gt;
&lt;p&gt;The first thing I really like is Pollen enables powerful text transformation using X-expressions. They’re like regular lisp S-expressions which models your document as a tree where transformations are easy.&lt;/p&gt;
&lt;p&gt;For example this expression:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;racket&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight racket&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta group quote pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;`(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;blockquote&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;Everyday life is like programming, I guess. If you love something you can put beauty into it.&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;footer&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta group pollen&quot;&gt;&lt;span class=&quot;punctuation definition group begin pollen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;author&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;Donald Knuth&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Corresponds to this html:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  Everyday life is like programming, I guess. If you love something you can put beauty into it.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Donald Knuth&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;blockquote&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Complex transformations really should be done with structured data, like X-expressions or ASTs in compilers, and not on raw html. It’s easier and less error prone.&lt;/p&gt;
&lt;p&gt;Secondly I actually like Pollen’s markup. It is more verbose than markdown—or others—but not unbearably so:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;Pollen markup&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;A link to &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;link&lt;/span&gt;&lt;span class=&quot;meta fun-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable other pollen&quot;&gt;my-site&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;my site&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;First item&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;Second item&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;Third item&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta parens pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊(&lt;/span&gt;&lt;span class=&quot;keyword control pollen&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;variable other pollen&quot;&gt;my-site&lt;/span&gt; &lt;span class=&quot;string quoted double lisp&quot;&gt;&lt;span class=&quot;punctuation definition string begin lisp&quot;&gt;&amp;quot;&lt;/span&gt;http://jonashietala.se&lt;span class=&quot;punctuation definition string end lisp&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;markdown&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight markdown&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta block-level markdown&quot;&gt;&lt;span class=&quot;markup heading 1 markdown&quot;&gt;&lt;span class=&quot;punctuation definition heading begin markdown&quot;&gt;#&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;markup heading 1 markdown&quot;&gt;&lt;span class=&quot;entity name section markdown&quot;&gt;Markdown markup&lt;/span&gt;&lt;span class=&quot;meta whitespace newline markdown&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta paragraph markdown&quot;&gt;A link to &lt;span class=&quot;meta link reference markdown&quot;&gt;&lt;span class=&quot;punctuation definition link begin markdown&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta link reference description markdown&quot;&gt;my site&lt;/span&gt;&lt;span class=&quot;meta link reference markdown&quot;&gt;&lt;span class=&quot;punctuation definition link end markdown&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta link reference markdown&quot;&gt;&lt;span class=&quot;punctuation definition constant begin markdown&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant other reference link markdown&quot;&gt;my-site&lt;/span&gt;&lt;span class=&quot;punctuation definition constant end markdown&quot;&gt;]&lt;/span&gt;&lt;/span&gt;.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup list unnumbered bullet markdown&quot;&gt;&lt;span class=&quot;punctuation definition list_item markdown&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;markup list unnumbered markdown&quot;&gt; &lt;span class=&quot;meta paragraph list markdown&quot;&gt;First item
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;markup list unnumbered bullet markdown&quot;&gt;&lt;span class=&quot;punctuation definition list_item markdown&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;markup list unnumbered markdown&quot;&gt;&lt;span class=&quot;meta paragraph list markdown&quot;&gt; Second item
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;markup list unnumbered bullet markdown&quot;&gt;&lt;span class=&quot;punctuation definition list_item markdown&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;markup list unnumbered markdown&quot;&gt;&lt;span class=&quot;meta paragraph list markdown&quot;&gt; Third item
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;markup list unnumbered markdown&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta link reference def markdown&quot;&gt;&lt;span class=&quot;punctuation definition constant begin markdown&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;entity name reference link markdown&quot;&gt;my-site&lt;/span&gt;&lt;span class=&quot;punctuation definition constant end markdown&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value markdown&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;markup underline link markdown&quot;&gt;http://jonashietala.se&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What it gives you is flexibility to freely define your tags however you want.&lt;/p&gt;
&lt;p&gt;See for example how I handled &lt;a href=&quot;/blog/2014/09/01/embedding_youtube_videos_with_hakyll/&quot;&gt;embedding youtube links&lt;/a&gt; on this site. I basically run a regex on the html to convert bare links (surrounded by a paragraph!):&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;https://www.youtube.com/watch?v=NIbr-mLi4DU
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;video-wrapper&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;video-container&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;iframe&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;//www.youtube.com/embed/NIbr-mLi4DU&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;frameborder&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;0&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name html&quot;&gt;allowfullscreen&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;iframe&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In Pollen you simply define a tag that returns the video-wrapper directly, so the markup is simple without magic:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;pollen&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight pollen&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;function magic pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;◊&lt;/span&gt;yt&lt;/span&gt;&lt;span class=&quot;meta curly-args pollen&quot;&gt;&lt;span class=&quot;punctuation magic group begin pollen&quot;&gt;{&lt;/span&gt;https://www.youtube.com/watch?v=NIbr-mLi4DU&lt;span class=&quot;punctuation magic group end pollen&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course you &lt;em&gt;could&lt;/em&gt; do string replacements as well if you want to, like if you want to convert “---” to “—” or “...” to “…”. But Pollen allows you to leave that to when it makes sense.&lt;/p&gt;
&lt;p&gt;Another consequence is you’re not limited to the features supported by your chosen markup. For instance if you want to add a footer in a quote with author and source links in markdown you need to drop down to raw html.&lt;/p&gt;
&lt;p&gt;An example that’s bothered me quite a bit is sidenotes. Markdown doesn’t support sidenotes. Neither does pandoc extended markdown, it only support footnotes but that’s not what I want. So my choice is to either create pandoc extensions myself or settle for raw html. With pollen you have full power to implement them in exactly the form you want.&lt;/p&gt;
&lt;p&gt;The drawback here is you have to implement the functionality yourself.&lt;/p&gt;
&lt;h1&gt;What I don’t like&lt;/h1&gt;
&lt;p&gt;Other static site generators allow you to route input files to output files. For example this site has post files like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;posts/2019-03-01-home_office_renovation.markdown
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which are routed to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;blog/2019/03/01/home_office_renovation/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To generate pretty urls. You’re also not limited to one output file or even an input file, you’re in full control.&lt;/p&gt;
&lt;p&gt;Pollen however has a one-to-one mapping of input and output files. So I cannot have a &lt;code&gt;posts&lt;/code&gt; directory with all my posts so I can list them in any easy manner but I would have to replicate the folder structure if I want to have any control over the output urls. This is bothersome.&lt;/p&gt;
&lt;p&gt;Another annoyance is output files are generated in the same directory as your input files. So while Hakyll collects outputs in a &lt;code&gt;_site&lt;/code&gt; directory, making it very easy to deploy a site, Pollen pollutes the base directory:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;site.html.pm    &lt;- input file in Pollen markup
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;site.html       &lt;- generated output file
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This probably bothers me much more than it should. I want order and cleanliness.&lt;/p&gt;
&lt;p&gt;Finally Pollen doesn’t handle dependencies very well. For example to update the output file I need to update the exact input file, even if the input file uses data from other files. Which it will do in for example table of content files.&lt;/p&gt;
&lt;p&gt;I had some trouble integrating sass for my css files. I used a system command which combines all .scss files to a single .css output file. I managed to get Pollen to do the generation for me but I couldn’t get it to track dependencies properly (so if I change any .scss file I want the .css to always regenerate).&lt;/p&gt;
&lt;p&gt;In the end I just threw together a simple script using &lt;code&gt;inotifywait&lt;/code&gt; which calls sassc when a .scss file change:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;!/bin/bash&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;sassc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; sass/main.scss&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;style&lt;/span&gt; compressed &lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;gt;&lt;/span&gt; css/main.css&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function echo shell&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;created: css/main.css&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;inotifywait&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;e&lt;/span&gt; close_write,moved_to,create&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;m&lt;/span&gt; sass/&lt;/span&gt; &lt;span class=&quot;keyword operator logical pipe shell&quot;&gt;|&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control while shell&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function read shell&quot;&gt;read&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; &lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;-&lt;/span&gt;r&lt;/span&gt; directory events filename&lt;/span&gt;&lt;span class=&quot;keyword operator logical continue shell&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;keyword control do shell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;sassc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; sass/main.scss&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;style&lt;/span&gt; compressed &lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;gt;&lt;/span&gt; css/main.css&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function echo shell&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;updated: css/main.css&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control done shell&quot;&gt;done&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This touches on my final annoyance with Pollen. Pollen only regenerates files when you ask for them. So you need to switch to the browser, refresh and Pollen only then starts creating your file. This usually takes a second or two but that’s long enough to be very annoying.&lt;/p&gt;
&lt;p&gt;Instead I want all my files to regenerate as soon as I save the file. This is how &lt;code&gt;inotifywait&lt;/code&gt; and to my knowledge all good static site generators including Hakyll work.&lt;/p&gt;
&lt;p&gt;Where Pollen makes the choice power over simplicity with it’s markup language it makes the opposite trade-off with the file handling. I would’ve liked it better if it chose power in both cases.&lt;/p&gt;
&lt;h1&gt;Should you use it?&lt;/h1&gt;
&lt;p&gt;The drawbacks I see are all related to file management and the benefit is the powerful markup.&lt;/p&gt;
&lt;p&gt;If you’re happy with the features markdown provides there are plenty of better alternatives. There are dirt simple site generators if you just want a site with minimal effort. Then there are libraries like Hakyll where you need to program a bit but you get more power.&lt;/p&gt;
&lt;p&gt;But if you require a more powerful markup language than what the alternatives like pandoc flavored markdown (which has a number of extensions compared to regular markdown) and you’re willing to put in work to make it the way you want it then Pollen is a good choice.&lt;/p&gt;
&lt;p&gt;If I were to write a book—which is Pollen’s reason of existance—I would probably choose Pollen. Maybe I’d try to improve the file handling or maybe learn to live with it.&lt;/p&gt;
&lt;p&gt;Will I migrate this blog to Pollen? While I would love the markup I’m not sure the effort is worth it. I would absolutely have to improve the file handling before I even consider it which probably means I won’t be bothered.&lt;/p&gt;
</content></entry><entry><title>Home office renovation</title><id>http://jonashietala.se/blog/2019/03/01/home_office_renovation/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/03/01/home_office_renovation" rel="alternate"/><published>2019-03-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;When we moved back to our childhood community and bought a house I had one pretty big requirement: I had to have a home office as I need to work remote. There simply isn’t any software development work for me here.&lt;/p&gt;
&lt;p&gt;So the later part of 2018 and early 2019 we’ve renovated an old storage room in the basement and made it into a home office. The storage area itself was moved into an old boiler room with more efficient shelving.&lt;/p&gt;
&lt;p&gt;I haven’t done any renovation project before and I can’t believe how long it took. It was just 1 room! Or 1.5 if we’re being honest.&lt;/p&gt;
&lt;p&gt;Unfortunately I didn’t take enough progress pictures and the before pictures were taken with some shoddy mobile camera. Hopefully you can get the idea anyway.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/home_office/IMG_20181029_192036792.jpg&quot;&gt;&lt;img src=&quot;/images/home_office/IMG_20181029_192036792.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/home_office/IMG_20181029_192135290.jpg&quot;&gt;&lt;img src=&quot;/images/home_office/IMG_20181029_192135290.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;This is the entrance. You enter from a dead end corridor.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My first thought was to tare down the wall to make a large room. Unfortunately it’s a supporting wall made of concrete.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/home_office/IMG_20181029_192120797.jpg&quot;&gt;&lt;img src=&quot;/images/home_office/IMG_20181029_192120797.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/home_office/IMG_20181029_192126989.jpg&quot;&gt;&lt;img src=&quot;/images/home_office/IMG_20181029_192126989.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;It comes with a nice color scheme and the distribution board.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The walls had some cracks and holes after we ripped out the shelves. The distribution board annoyed me as it takes up a whole wall which might have been perfect for shelves or a whiteboard.&lt;/p&gt;
&lt;p&gt;We got help from Veronica’s sister’s boyfriend who’s a painter to take care of the walls. I was planning to put up a whiteboard but we opted to wait and see where to best place it.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/home_office/IMG_20181230_142939907.jpg&quot;&gt;&lt;img src=&quot;/images/home_office/IMG_20181230_142939907.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/home_office/IMG_20181230_142951245.jpg&quot;&gt;&lt;img src=&quot;/images/home_office/IMG_20181230_142951245.jpg&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;These are the only in-progress pics I have. We’re in the middle of gluing the ceiling plates.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For the ceiling I got some sound dampening plates (is the plate the right word? They’re quite soft) which we glued to boards we nailed to the ceiling. I was &lt;em&gt;really&lt;/em&gt; worried when we were putting them up that they would look misaligned or weird but they actually turned out very well.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/home_office/DSC00314.JPG&quot; /&gt;
&lt;figcaption&gt;Ceiling with LED lights.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I got some high quality LED panels for lighting. Lighting is important as you can get headache if you sit in a room long periods if it’s poorly lit or poor quality lights. I had some mounts as well but they didn’t really work so we just hung them up on some wires. Not as pretty but I really don’t notice it.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/home_office/DSC00312.JPG&quot;&gt;&lt;img src=&quot;/images/home_office/DSC00312.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/home_office/DSC00313.JPG&quot;&gt;&lt;img src=&quot;/images/home_office/DSC00313.JPG&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;The distribution board is hidden away nicely behind an IKEA kitchen cupboard.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/home_office/DSC00310.JPG&quot; /&gt;
&lt;figcaption&gt;Here the renovation is done. Naturally the computer is the first thing up.&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/home_office/DSC00311.JPG&quot; /&gt;
&lt;figcaption&gt;A green broadloom on the floor&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We didn’t bother to remove the existing glued carpet and instead just added a carpet on top. Work smarter not harder.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/home_office/DSC00339.JPG&quot;&gt;&lt;img src=&quot;/images/home_office/DSC00339.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/home_office/DSC00343.JPG&quot;&gt;&lt;img src=&quot;/images/home_office/DSC00343.JPG&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;For now I have two desks. When there’s space it gets filled quickly.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I bought a new desk from Kinnarps so I can alter sitting and standing. I’ve been using it for about a month now and while I should change more often I do stand a few hours per day.&lt;/p&gt;
&lt;p&gt;My old desk also fits which is excellent for my hardware projects, LEGO builds or just as a place to offload stuff.&lt;/p&gt;
&lt;p&gt;Yes it’s a bit of a man-cave as well as an office.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/home_office/DSC00341.JPG&quot; width=&quot;50%&quot; /&gt;
&lt;figcaption&gt;What to do with an inefficient corridor? A home gym!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Now having a home office and a man cave is a luxury, it really is. But having a home gym right next to it takes it to a whole new level.&lt;/p&gt;
&lt;p&gt;Usually the last 2-3 hours of a whole day of programming were much, much slower and heavier than the first very productive hours for me. Going to the gym over lunch often gave me energy to push through the latter half of the day with relatively high productivity and without tanking my energy levels.&lt;/p&gt;
&lt;p&gt;What I can do now is even better. I can work, then do a quick set as a break, then work etc. This keeps my energy levels and productivity high throughout the day.&lt;/p&gt;
</content></entry><entry><title>Regex substitution with unicode in Haskell</title><id>http://jonashietala.se/blog/2019/01/25/regex_substitution_with_unicode_in_haskell/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/01/25/regex_substitution_with_unicode_in_haskell" rel="alternate"/><published>2019-01-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;While &lt;a href=&quot;/blog/2019/01/25/site_restyle_and_update/&quot; title=&quot;Site restyle and update&quot;&gt;remaking the site&lt;/a&gt; I noticed &lt;a href=&quot;/blog/2014/09/01/embedding_youtube_videos_with_hakyll/&quot; title=&quot;Embedding youtube videos with Hakyll&quot;&gt;my automatic embedding of bare youtube links&lt;/a&gt; sometimes didn’t work. The culprit was unicode in the document which the regex library couldn’t handle.&lt;/p&gt;
&lt;p&gt;Apparently while this would be supported by default by almost all modern languages it’s not the case with Haskell. I tried several regex libraries which either didn’t support substitutions or couldn’t handle unicode properly.&lt;/p&gt;
&lt;p&gt;As usual &lt;a href=&quot;https://stackoverflow.com/questions/45067622/how-to-find-and-replace-unicode-chars-in-haskell&quot;&gt;others&lt;/a&gt; have &lt;a href=&quot;https://stackoverflow.com/questions/3847475/haskell-regex-substitution&quot;&gt;had&lt;/a&gt; this before me. This is the most elegant working solution I could find:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta import haskell&quot;&gt;&lt;span class=&quot;keyword other haskell&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;keyword other haskell&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;support other module haskell&quot;&gt;Text.Regex.PCRE.Light&lt;/span&gt; &lt;span class=&quot;keyword other haskell&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;support other module haskell&quot;&gt;RL&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta import haskell&quot;&gt;&lt;span class=&quot;keyword other haskell&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;keyword other haskell&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;support other module haskell&quot;&gt;Text.Regex.PCRE.Heavy&lt;/span&gt; &lt;span class=&quot;keyword other haskell&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;support other module haskell&quot;&gt;RH&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash haskell&quot;&gt;&lt;span class=&quot;punctuation definition comment haskell&quot;&gt;--&lt;/span&gt; Find and replace bare youtube links separated by &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;youtubeFilter&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;youtubeFilter txt &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;constant other haskell&quot;&gt;RH&lt;/span&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt;gsub rx replace txt
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword other haskell&quot;&gt;where&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      rx &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant other haskell&quot;&gt;RL&lt;/span&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt;compile &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;p&amp;gt;&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;s*https?://www&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;.youtube&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;.com/watch&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;?v=([A-Za-z0-9_-]+)&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;s*&amp;lt;/p&amp;gt;&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                      [&lt;span class=&quot;constant other haskell&quot;&gt;RL&lt;/span&gt;&lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt;utf8]
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      replace &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;\&lt;/span&gt;[g] &lt;span class=&quot;keyword operator haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;div class=&lt;span class=&quot;constant character escape haskell&quot;&gt;\&amp;quot;&lt;/span&gt;video-wrapper&lt;span class=&quot;constant character escape haskell&quot;&gt;\&amp;quot;&lt;/span&gt;&amp;gt;\&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 &lt;span class=&quot;keyword operator haskell&quot;&gt;\&amp;lt;&lt;/span&gt;div &lt;span class=&quot;meta declaration class haskell&quot;&gt;&lt;span class=&quot;keyword other haskell&quot;&gt;class&lt;/span&gt;=\&amp;quot;&lt;span class=&quot;variable other generic-type haskell&quot;&gt;video&lt;/span&gt;-&lt;span class=&quot;variable other generic-type haskell&quot;&gt;container&lt;/span&gt;\&amp;quot;&amp;gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                   \&amp;lt;&lt;span class=&quot;variable other generic-type haskell&quot;&gt;iframe&lt;/span&gt; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;src&lt;/span&gt;=\&amp;quot;//&lt;span class=&quot;variable other generic-type haskell&quot;&gt;www&lt;/span&gt;.&lt;span class=&quot;variable other generic-type haskell&quot;&gt;youtube&lt;/span&gt;.&lt;span class=&quot;variable other generic-type haskell&quot;&gt;com&lt;/span&gt;/&lt;span class=&quot;variable other generic-type haskell&quot;&gt;embed&lt;/span&gt;/&amp;quot; ++ &lt;span class=&quot;variable other generic-type haskell&quot;&gt;g&lt;/span&gt; ++ &amp;quot;\&amp;quot; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;frameborder&lt;/span&gt;=\&amp;quot;0\&amp;quot; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;allowfullscreen&lt;/span&gt;/&amp;gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                 \&amp;lt;/&lt;span class=&quot;variable other generic-type haskell&quot;&gt;div&lt;/span&gt;&amp;gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;              \&amp;lt;/&lt;span class=&quot;variable other generic-type haskell&quot;&gt;div&lt;/span&gt;&amp;gt;&amp;quot;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is to say it’s not very elegant but it does get the job done.&lt;/p&gt;
</content></entry><entry><title>Site restyle and update</title><id>http://jonashietala.se/blog/2019/01/25/site_restyle_and_update/index.html</id><updated>2026-04-27T11:10:46+00:00</updated><link href="https://www.jonashietala.se/blog/2019/01/25/site_restyle_and_update" rel="alternate"/><published>2019-01-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’m not sure how I got started but I recently read an excellent book about typography: &lt;a href=&quot;https://practicaltypography.com/&quot; title=&quot;Practical Typography&quot;&gt;Butterick’s Practical Typography&lt;/a&gt;. It’s free and there’s a section &lt;a href=&quot;https://practicaltypography.com/typography-in-ten-minutes.html&quot; title=&quot;Practical Typography: Typography in ten minutes&quot;&gt;Typography in ten minutes&lt;/a&gt; if you want the important bits.&lt;/p&gt;
&lt;p&gt;He makes a pretty good case for &lt;a href=&quot;https://practicaltypography.com/why-typography-matters.html&quot; title=&quot;Practical Typography: Why typography matters&quot;&gt;why it matters&lt;/a&gt; when he points out the vast majority of a webpage is text. Despite this it seems focus is on color schemes, images and effects. As I was already leaning towards minimalistic sites over bloated crap I decided to do a makeover of this site after reading the book.&lt;/p&gt;
&lt;h1&gt;Problems with my previous site&lt;/h1&gt;
&lt;p&gt;I was pretty happy with the site I had. But as I looked closer there were issues.&lt;/p&gt;
&lt;p&gt;Butterick lists &lt;a href=&quot;https://practicaltypography.com/websites.html&quot; title=&quot;Practical Typography: websites&quot;&gt;5 anti-habits&lt;/a&gt; websites do and I managed to tick four out of five ant-habits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tiny font size for body text&lt;/li&gt;
&lt;li&gt;Huge size for headings&lt;/li&gt;
&lt;li&gt;Relied on system fonts like Arial and Georgia&lt;/li&gt;
&lt;li&gt;Huge block of eye catching color for header and footer&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The only one I managed to avoid was having page edges crammed with wads of navigational links.&lt;/p&gt;
&lt;p&gt;The site also wasn’t responsive so it looked like shit on mobile and had very long lines on bigger screens making it hard to read.&lt;/p&gt;
&lt;h1&gt;Text improvements&lt;/h1&gt;
&lt;p&gt;The major changes were naturally to correct the big anti-habits and other no-nos the book brings up.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/site_restyle/old_post.png&quot;&gt;&lt;img src=&quot;/images/site_restyle/old_post.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/site_restyle/new_post.png&quot;&gt;&lt;img src=&quot;/images/site_restyle/new_post.png&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Old post style vs new post style&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When comparing the old post style with the new we can pick out some noticeable changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The body text is larger to make it easier to read.&lt;/li&gt;
&lt;li&gt;Margins are larger to keep lines at 2-3 alphabets—an easy way to gauge how long lines should be.&lt;/li&gt;
&lt;li&gt;Headers aren’t enormous compared to everything else yet easily identifiable.&lt;/li&gt;
&lt;li&gt;Tighter whitespace&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you look closely enough you can also see the fonts are different. &lt;a href=&quot;https://practicaltypography.com/century-supra.html&quot; title=&quot;Century Supra font&quot;&gt;Century Supra&lt;/a&gt; is the new body text replacing Georgia and &lt;a href=&quot;https://practicaltypography.com/concourse.html&quot; title=&quot;Concourse font&quot;&gt;Concourse&lt;/a&gt; is used for the date and navigation links. They are both professional fonts made by the author of &lt;a href=&quot;https://practicaltypography.com/&quot; title=&quot;Practical Typography&quot;&gt;Practical Typography&lt;/a&gt;.&lt;/p&gt;
&lt;aside&gt;I didn’t know this before, and it bothered me, but take a look at the old post. Some of the numbers are off centered, 5 is slightly lower than the others for example. They’re numbers in an old style some fonts support. &lt;a href=&quot;https://practicaltypography.com/century-supra.html&quot; title=&quot;Century Supra font&quot;&gt;Century Supra&lt;/a&gt; supports it as well via a setting which I haven’t turned on.&lt;/aside&gt;
&lt;p&gt;Now here’s the kicker: the fonts cost $239. And still I bought them.&lt;/p&gt;
&lt;p&gt;Are the free fonts so bad? Absolutely not and Butterick &lt;a href=&quot;https://practicaltypography.com/free-fonts.html&quot; title=&quot;Practical Typography: Free fonts&quot;&gt;agrees&lt;/a&gt;. I do like the fonts but the main reason I bought them was to support the book. The book is completely free and instead he’s trying to make money by selling fonts. I want to support him and if I get something good in return then great.&lt;/p&gt;
&lt;h1&gt;Responsive layout&lt;/h1&gt;
&lt;p&gt;I’m not really a web designer so this was my first time trying to make a responsive design. &lt;a href=&quot;https://css-tricks.com/snippets/css/a-guide-to-flexbox/&quot; title=&quot;A guide to flexbox&quot;&gt;Flexbox&lt;/a&gt; combined with some media queries made the process pretty straight forward.&lt;/p&gt;
&lt;p&gt;Reading the site on a phone should now resize the font from 22px to 16px—or something in between—and re-flow the layout. I tried a multi-column layout for the &lt;a href=&quot;/&quot;&gt;homepage&lt;/a&gt; and &lt;a href=&quot;/projects&quot;&gt;projects page&lt;/a&gt; to better utilize space on wider screens which turns into a single-column on smaller screens.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/site_restyle/old_homepage.png&quot;&gt;&lt;img src=&quot;/images/site_restyle/old_homepage.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/site_restyle/new_homepage.png&quot;&gt;&lt;img src=&quot;/images/site_restyle/new_homepage.png&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;The old home page vs the new home page&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’m not completely happy with how the tags are laid out but it will do for now. I do think the homepage is an improvement at least.&lt;/p&gt;
&lt;h1&gt;Changes to code display&lt;/h1&gt;
&lt;p&gt;While I was looking to change font for my main text I started looking at programming fonts as well. It’s a huge rabbit hole I might write more about in the future.&lt;/p&gt;
&lt;p&gt;For the site I changed the default coding font from Consolas —which is proprietary to Windows— to &lt;a href=&quot;https://sourcefoundry.org/hack/&quot; title=&quot;Hack font&quot;&gt;Hack&lt;/a&gt;. As a bonus &lt;a href=&quot;https://sourcefoundry.org/hack/&quot; title=&quot;Hack font&quot;&gt;Hack&lt;/a&gt; is completely free and hackable.&lt;/p&gt;
&lt;p&gt;I use dark background color personally but I’m not a fan of it on websites as they draw too much attention from the body text. The color &lt;a href=&quot;/blog/2015/08/04/gruvbox_syntax_highlighting_for_pandoc/&quot; title=&quot;Gruvbox syntax highlighting for pandoc&quot;&gt;I had used&lt;/a&gt; from the gruvbox theme was also quite eye catching so I chose a softer one. After updating pandoc I found a couple of new highlighting classes as well.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/site_restyle/old_code.png&quot;&gt;&lt;img src=&quot;/images/site_restyle/old_code.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/site_restyle/new_code.png&quot;&gt;&lt;img src=&quot;/images/site_restyle/new_code.png&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;Old code vs new code&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;See the &lt;a href=&quot;https://codeberg.org/treeman/jonashietala/src/branch/master/css/code.scss&quot; title=&quot;Sass markup for code&quot;&gt;source&lt;/a&gt; if you’re curious.&lt;/p&gt;
&lt;h1&gt;Other changes&lt;/h1&gt;
&lt;p&gt;I did a bunch of other things as well while I was at it. Such as adding game images to the &lt;a href=&quot;/projects&quot;&gt;projects&lt;/a&gt; page, correcting html5 markup and rewrote the styling in sass.&lt;/p&gt;
&lt;p&gt;One annoyance I never bothered to fix was tag links generated links with mixed case and spaces. Now instead of &lt;code&gt;/blog/tags/Yearly Review&lt;/code&gt; we get &lt;code&gt;/blog/tags/yearly_review&lt;/code&gt;. It can be accomplished in Hakyll by using a custom route:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;tagRoute&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;Routes&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;tagRoute &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;(customRoute &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; (map toLower) &lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt; (replace &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;_&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt; toFilePath) &lt;span class=&quot;keyword operator function infix haskell&quot;&gt;&lt;span class=&quot;punctuation definition entity haskell&quot;&gt;`&lt;/span&gt;composeRoutes&lt;span class=&quot;punctuation definition entity haskell&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;           gsubRoute &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;tags/&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; (const &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;blog/tags/&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword operator function infix haskell&quot;&gt;&lt;span class=&quot;punctuation definition entity haskell&quot;&gt;`&lt;/span&gt;composeRoutes&lt;span class=&quot;punctuation definition entity haskell&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;           dropIndexRoute
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>2018 in review</title><id>http://jonashietala.se/blog/2019/01/24/2018_in_review/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2019/01/24/2018_in_review" rel="alternate"/><published>2019-01-24T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A new year and a lingering feeling of not having done enough during the year. A fast review of the year usually makes me feel better.&lt;/p&gt;
&lt;h1&gt;2018 non-geek achievements&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Was on parental leave for about 7 months.&lt;/p&gt;
&lt;p&gt;It was great although I’ve been crawling up the walls a little the last month.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Moved to a small village or society far from Linköping. But kept the job.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote &lt;a href=&quot;/archive&quot; title=&quot;My archive&quot;&gt;5 blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2018 geek achievements&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Read through the book &lt;a href=&quot;https://practicaltypography.com/&quot; title=&quot;Practical Typography&quot;&gt;Practical Typography&lt;/a&gt; and restyled this site to try and internalize the concepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a lot of manga and light novels.&lt;/p&gt;
&lt;p&gt;I’ve tried to keep lists of what I read and watch but I just can’t do it consistently so I’ve stopped trying.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2018 failures&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;I didn’t write much at all during the year.&lt;/li&gt;
&lt;li&gt;No time for hobby projects.&lt;/li&gt;
&lt;li&gt;Read very little.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Plans for 2019&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Gonna start working remote full time, with occasional travel.&lt;/li&gt;
&lt;li&gt;Make an effort to write more. Both shorter posts and longer articles.&lt;/li&gt;
&lt;li&gt;Spend time on side projects and improving skills.&lt;/li&gt;
&lt;li&gt;Try to get consistent grappling training. It’s a &lt;em&gt;small&lt;/em&gt; hurdle there’s no submission wrestling or BJJ here.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>HandCash handles require trust and are insecure</title><id>http://jonashietala.se/blog/2018/09/22/handcash_handles_are_centralized_and_insecure/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2018/09/22/handcash_handles_are_centralized_and_insecure" rel="alternate"/><published>2018-09-22T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The &lt;a href=&quot;https://handcash.io&quot; title=&quot;HandCash Bitcoin Cash wallet&quot;&gt;HandCash&lt;/a&gt; wallet has recently become a popular Bitcoin Cash wallet in large part thanks to their $handle concept. It’s basically a username you use instead of the normal Bitcoin Cash address, similar to how domain names abstract away IP addresses.  For example instead of sending BCH to my address&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;bitcoincash:qr6nm0wrkqata3klatmeuzqkjjvu725rkslzsahs8f
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;you can instead send it to &lt;code&gt;$treeman&lt;/code&gt;. Much more user friendly, right?&lt;/p&gt;
&lt;h1&gt;Third party trust&lt;/h1&gt;
&lt;p&gt;However there are problems. The $handle to address mapping is kept on the wallet developers’ own centralized servers. This means they could reroute all payments to any handle to some other address (unless the sending wallet has already cached the address).&lt;/p&gt;
&lt;p&gt;This is a huge risk and central point of failure which in my opinion doesn’t belong a decentralized payment system. When you pay to a $handle you’re basically trusting them not to steal your payment and that their servers are secure. The whole point of a cryptocurrency is to remove reliance on a third party which is reintroduced by $handles.&lt;/p&gt;
&lt;p&gt;They’ve said they’ll open up the handle API so other wallets could use them but we should instead come up with a decentralized username system. Or try to find other ways of communicating addresses instead of having to type them in manually. For example via NFC (which HandCash also has) or QR codes (which have been used since forever).&lt;/p&gt;
&lt;p&gt;A side note on the trust issue: &lt;em&gt;the HandCash wallet itself is also closed source&lt;/em&gt;. I would never use a closed source wallet to store my coins and neither should you.&lt;/p&gt;
&lt;h1&gt;No checksum or identification&lt;/h1&gt;
&lt;p&gt;What happens if you type &lt;code&gt;$treman&lt;/code&gt; instead of &lt;code&gt;$treeman&lt;/code&gt;? You will send your payment to someone else.&lt;/p&gt;
&lt;p&gt;The Bitcoin Cash address has a checksum built in, similar to credit card numbers, social security numbers and virtually everything else you usually type in by hand. For good reason since it’s very common to fat finger and mess up. This isn’t something handles can provide.&lt;/p&gt;
&lt;p&gt;Instead of checksums some systems they require confirmation with the receiver’s identification. For example Swish, a popular Swedish payment system, allows you to send a payment connected to a phone number. They then display the receiver’s name before you confirm the payment.&lt;/p&gt;
&lt;p&gt;You could think it’s possible modify handles to do something similar. Maybe I could attach my name to &lt;code&gt;$treeman&lt;/code&gt; so you know you’re sending it to me? But where Swish uses Sweden’s national identification system BankID Bitcoin Cash should be a permissionless and trustless system. There is nothing preventing someone from attaching my name to &lt;code&gt;$treman&lt;/code&gt; and pretending to be me. The problem is similar to look-alike domains which is fundamentally hard to solve in a decentralized handles context.  Compare it with normal addresses where it’s practically impossible to generate look-alike addresses.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;While I like the idea of simplifying addresses and making them more user friendly there are large problems with HandCash handles. Having to trust a third party for handle resolution and them being less safe to type makes them much less secure than normal addresses and should only be used for small amounts.&lt;/p&gt;
&lt;p&gt;Instead we could focus on alternatives to avoid having to type anything at all. For example QR codes, NFC or bluetooth could help bridge the gaps. The one example where I still find friction is when sending coins from my desktop wallet to my phone wallet which I work around by copying my address and saving a email draft and visually inspecting it before sending.&lt;/p&gt;
</content></entry><entry><title>Bitcoin Cash needs a Specification</title><id>http://jonashietala.se/blog/2018/07/30/bitcoin_cash_needs_a_specification/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2018/07/30/bitcoin_cash_needs_a_specification" rel="alternate"/><published>2018-07-30T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’m not a Bitcoin developer, I’m just some guy looking in from the outside. Lately there’s been a bunch of heated debates between the different Bitcoin Cash developer teams. Something that stood out from all the noise was problems with communications and a lack of specification for new proposals. Thinking about it there’s no specification at all.&lt;/p&gt;
&lt;h1&gt;A full specification&lt;/h1&gt;
&lt;p&gt;Since Satoshi released the Bitcoin protocol it’s been specified by the reference client and &lt;a href=&quot;https://en.bitcoin.it/wiki/Protocol_documentation&quot;&gt;Bitcoin Core is still referred as such&lt;/a&gt;. It’s argued that this is by design as it would avoid accidental hard fork splits if a bug would deviate from the consensus rules. The drawback is that a flaw could bring the whole network down.&lt;/p&gt;
&lt;p&gt;After the split to Bitcoin Cash there’s no longer a reference client. Instead there are several different clients that follows the consensus rules. This makes the network more durable as it’s less probable that a flaw could exploit all clients and instead the risk for an accidental hard fork is higher since clients may have small bugs in their consensus rules. Therefore a lot of importance needs to be placed on making sure the different clients use the same consensus rules and bugs there are discovered.&lt;/p&gt;
&lt;p&gt;This makes the lack of a specification baffling. It’s easier to find higher level bugs in a specification and clients can focus on implementing the spec instead of trying to match their implementation with each others.&lt;/p&gt;
&lt;p&gt;It also makes it harder to create new clients. Today the best option is to just fork the code of an existing implementation and modifying it. Of course this includes importing all technical debt and potentially crappy implementations to your client. It also constrains you to use C++, if you want to create a new highly-reliable client using Erlang then you have a bunch of reverse engineering and converting to do.&lt;/p&gt;
&lt;p&gt;Therefore there should be a full specification of the Bitcoin Cash protocol. It should be so complete you should be able to create a new client with the spec as a reference without having to read the code of other implementations.&lt;/p&gt;
&lt;h1&gt;Improvement Proposals&lt;/h1&gt;
&lt;p&gt;It’s hard to develop software with a single team and harder to develop software with multiple teams. It’s much harder if improvements and changes doesn’t come with a specification and essential details can only be found by examining reference code implemented in an unfamiliar code base.&lt;/p&gt;
&lt;p&gt;In the case of consensus changes this is very dangerous and small but important implementation details are easily missed. It not only makes the changes harder to implement for the different developer teams but it’s also much harder to do security reviews for.  Importantly it makes discussions, feedbacks and reviews of the changes themselves difficult for the different developer teams.&lt;/p&gt;
&lt;p&gt;Even optional features, like block relay networks, would benefit. Otherwise we’ll run into issues like some clients implementing Xthin and others implementing Compact blocks instead due to missing specs and design flaws. It would be much better if all clients would work together and utilize the same infrastructure.&lt;/p&gt;
&lt;p&gt;Due to communication challenges between teams perhaps it might be time to collectively work on Bitcoin Cash Improvement Proposals, similar to the &lt;a href=&quot;https://github.com/bitcoin/bips&quot;&gt;BIPS of Bitcoin Core&lt;/a&gt;, where features could be discussed? Naturally all proposals should require complete specs.&lt;/p&gt;
&lt;p&gt;It’s of course not this straight forward in practice. There will always be discussions, both internal and external, in other channels but it’s still important to have a public process like this where feedback and scrutiny can be collected community wide.&lt;/p&gt;
&lt;p&gt;It would be hugely beneficial for the development of Bitcoin Cash if the different developer teams could agree on some common process.&lt;/p&gt;
</content></entry><entry><title>2017 in Review</title><id>http://jonashietala.se/blog/2018/07/28/2017_in_review/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2018/07/28/2017_in_review" rel="alternate"/><published>2018-07-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;In contrast to &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly reviews&quot;&gt;previous years&lt;/a&gt; I haven’t kept up with the blog. For good reason I’d say since we got a child in October! It really alters your perspectives and other things suddenly feel a little less important and of course there’s less time to do other stuff.&lt;/p&gt;
&lt;p&gt;A little late and incomplete perhaps but at least I’ll try to have an unbroken streak of reviews.&lt;/p&gt;
&lt;h1&gt;2017 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Got a kid!&lt;/li&gt;
&lt;li&gt;Wrote &lt;a href=&quot;/archive&quot; title=&quot;My archive&quot;&gt;6 blog posts&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2017 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Picked my first lock.&lt;/li&gt;
&lt;li&gt;Studied a little Korean (haphazardly…).&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2017 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;No hobby programming.&lt;/li&gt;
&lt;li&gt;Didn’t read enough books.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2018&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Take care of Veronica and Isidor.&lt;/li&gt;
&lt;li&gt;Parental leave.&lt;/li&gt;
&lt;li&gt;Move to a house in another part of the country.&lt;/li&gt;
&lt;li&gt;Write some more.&lt;/li&gt;
&lt;li&gt;Read some more.&lt;/li&gt;
&lt;li&gt;Train some more.&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>Bitcoin&apos;s security isn&apos;t binary</title><id>http://jonashietala.se/blog/2018/07/28/bitcoins_security_isnt_binary/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2018/07/28/bitcoins_security_isnt_binary" rel="alternate"/><published>2018-07-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’d like to address a misconception that’s at the core in many Bitcoin discussions lately: Bitcoin’s security isn’t binary. In fact security in general isn’t black and white. It’s a trade-off being secure enough for your threat model vs the cost and feasibility of your protection.&lt;/p&gt;
&lt;p&gt;Consider having your front door locked for example. You could consider your home secure if your door is locked and insecure if it’s open but that doesn’t say what you’re secure against. It’s missing context. It might prevent opportunistic thefts but a more determined attacker could instead break a window, pick the lock of the door or simply break down the door itself. Maybe you live in a neighborhood with lots of thefts and you might want an alarm system, a dog or iron bars over your windows.&lt;/p&gt;
&lt;p&gt;At the same time it might not be practical to go all out and get the best protection possible. You might not want to give up your life and move to a bunker where your friends can’t visit and a private security force may be slightly too expensive.&lt;/p&gt;
&lt;p&gt;In practice locking your door is good enough for many people. Some people do more and there are many options for them including private security for celebrities. That’s okay since threat models and feeling of security is different for everyone. This is the case for Bitcoin as well. Some sell houses for Bitcoin and have high security requirements while others sell coffee and have less. Unfortunately people, including developers, don’t acknowledge that Bitcoin is more fine grained than “secure” and “insecure”.&lt;/p&gt;
&lt;h1&gt;Double spend protection &amp;amp; Confirmations&lt;/h1&gt;
&lt;p&gt;An essential security feature of Bitcoin is double spend protection. It solves it using Proof-of-Work where each block containing a set of transactions is expensive to make and each block build on the previous block. If you want to reverse a transaction to double spend it you need to redo the work of all blocks until you find the transaction. This makes a transaction deeper in the blockchain, with more confirmations, more secure than one with less confirmations since an attacker would need more work to reverse it.&lt;/p&gt;
&lt;p&gt;This maps well to different security requirements. One confirmation is good enough for small value goods but exchanges might want to wait six confirmations instead, which has been the default recommendation for the paranoid a while.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.trustnodes.com/2018/05/24/bitcoin-gold-51-attacked-18-million-stolen-double-spends&quot; title=&quot;Bitcoin Gold 51% Attacked, $18 Million Stolen Through Double Spends&quot;&gt;A double spend attack was used in the wild to reverse transactions 22 blocks deep in Bitcoin Gold in May&lt;/a&gt;. Bitcoin isn’t as easily attacked since there’s not enough mining power mining other coins that can simply be temporarily rerouted for the attack but it demonstrates the attack nicely.&lt;/p&gt;
&lt;p&gt;At the time of writing a miner is rewarded 12.5 BTC for each block found, approximately $80 000. For an attack to be worth it the double spends need to outweigh the costs of leaving out potential mining profits. This makes all but very large sums safe enough to accept with a single confirmation.&lt;/p&gt;
&lt;p&gt;If you want to learn more I heartily recommend &lt;a href=&quot;https://bitcoin.com/bitcoin.pdf&quot; title=&quot;Bitcoin: A Peer-to-Peer Electronic Cash System&quot;&gt;the whitepaper&lt;/a&gt; which is quite easy to read.&lt;/p&gt;
&lt;h1&gt;0-conf&lt;/h1&gt;
&lt;p&gt;Transactions without a single confirmation, abbreviated 0-conf, by definition aren’t included in the blockchain and don’t get the double spend protection confirmed transactions do. That makes them completely insecure and should never be used, or that’s what some opponents tell you.&lt;/p&gt;
&lt;p&gt;Firstly all physical goods purchased online have an inherent delivery delay. The worst that can happen if you accept a 0-conf transaction that gets double spent is you have to cancel the order. Instead if you wait for a confirmation, which on average takes 10 min but might be up to an hour, you introduce an annoying wait time for your customers.&lt;/p&gt;
&lt;p&gt;But what’s really annoying is when you want to buy things in physical stores. It might be okay to wait for a confirmation email for some online purchases but it’s completely unacceptable to have to wait 10-60 min for your coffee until your transaction is confirmed (this example is always brought up). Someone could indeed double spend and steal a coffee. That’s bad but it’s actually not too different from what already have today. VISA allows charge backs &lt;a href=&quot;https://chargeback.com/visa-chargeback-time-limits/&quot; title=&quot;Visa Chargeback Time Limits&quot;&gt;up to 120 days&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Chargeback_fraud&quot; title=&quot;Chargeback fraud&quot;&gt;charge back fraud&lt;/a&gt; is a common problem for merchants. If you accept cash you risk getting counterfeit bills and you always run the risk of plain old shopliftig.&lt;/p&gt;
&lt;p&gt;Some claim it’s very easy to double spend 0-conf. &lt;a href=&quot;https://twitter.com/peterktodd/status/686365181241212928&quot; title=&quot;Peter Todd on Twitter: its already trivial to send an easy to doublespend tx&quot;&gt;Here’s a tweet&lt;/a&gt; from Core developer Peter Todd:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Why opt-in RBF doesn’t change zeroconf security; its already trivial to send an easy to doublespend tx.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s only true if you naively accept 0-conf. There are strategies you can use to minimize the risk of a double spend which defeats trivial double spend scripts Peter is referring to. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Silently sample random nodes to increase the confidence that the transaction has been propagated through the network&lt;/li&gt;
&lt;li&gt;Wait a few seconds and look for double spends&lt;/li&gt;
&lt;li&gt;Require a fee that’s probable to be accepted in the next block&lt;/li&gt;
&lt;li&gt;Use external identification like security cameras or ID cards to dissuade fraud&lt;/li&gt;
&lt;li&gt;For high risk transactions instead wait for confirmations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Research on how to improve 0-conf is ongoing. See for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://users.encs.concordia.ca/~clark/biblio/bitcoin/Karame%202015.pdf&quot;&gt;Double-spending Prevention for Bitcoin zero-confirmation transactions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eprint.iacr.org/2017/394.pdf&quot;&gt;Misbehavior in Bitcoin: A Study of Double-Spending and Accountability&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these heuristics accepting 0-conf is a viable alternative for some merchants. It’s not completely secure but it’s not completely insecure either. After all the competition isn’t much better and the benefits are huge, waiting a couple of seconds vs 10 min. It’s also completely up to the merchant’s discretion if she wants to use it or not.&lt;/p&gt;
&lt;p&gt;Despite this Bitcoin Core developers have treated 0-conf as insecure and have adopted policies that actively makes it worse. Full blocks, where all transactions compete in fees to be included, makes 0-conf unreliable because fees cannot be predicted with confidence. In December fees grew to $60 but it simply wasn’t a priority to increase the block size so one can assume full blocks fits the developers’ plan for Bitcoin and 0-conf does not.&lt;/p&gt;
&lt;p&gt;They also adopted &lt;a href=&quot;https://bitcoin.stackexchange.com/questions/10733/what-is-replace-by-fee&quot; title=&quot;What is Replace By Fee&quot;&gt;RBF&lt;/a&gt; in the Bitcoin reference client Bitcoin Core. It’s a convenient method to alter the fee &lt;em&gt;and outputs&lt;/em&gt; of an unconfirmed transaction. As it’s implemented in the reference client miners and wallets naturally supports it. In other words they made double spending more user friendly than before instead of adopting policies that would make 0-conf more secure “because it’s already insecure”.&lt;/p&gt;
&lt;h1&gt;SPV &amp;amp; full nodes&lt;/h1&gt;
&lt;p&gt;Jonald Fyookball wrote a good &lt;a href=&quot;https://medium.com/@jonaldfyookball/why-every-bitcoin-user-should-understand-spv-security-520d1d45e0b9&quot;&gt;article on SPV security&lt;/a&gt;, I suggest you read it if you haven’t already.&lt;/p&gt;
&lt;p&gt;In short an SPV wallet avoids the need to download and store the whole blockchain just to be able to send and receive transactions. Basically all mobile wallets work this way. An SPV wallet is indeed less secure than a full node but it’s not completely insecure (again, security is on a spectrum).&lt;/p&gt;
&lt;p&gt;What an SPV wallet does for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensures your transactions are in a block&lt;/li&gt;
&lt;li&gt;It tracks the Proof-of-Work of the blocks, i.e. follows the longest chain&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What it doesn’t do for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Validates transactions inside a block&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means a miner can create a block with transactions that sends any number of coins from any address. That sounds bad, but realize that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can only fool the SPV wallet if you provide the longest chain&lt;/li&gt;
&lt;li&gt;The miner must pay the POW cost of creating the block(s)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So to fool you the miner must, at least temporarily, outproduce the rest of the network. This isn’t possible in the long run if the core security assumption of Bitcoin holds: that a majority of miners are honest.&lt;/p&gt;
&lt;p&gt;But it’s theoretically possible and thus businesses like exchanges and payment processors would still want full nodes for the extra security. &lt;a href=&quot;https://bitcoin.com/bitcoin.pdf&quot; title=&quot;Bitcoin: A Peer-to-Peer Electronic Cash System&quot;&gt;Satoshi agrees&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Businesses that receive frequent payments will probably still want to run their own nodes for more independent security and quicker verification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most SPV users are normal people who mostly use wallets to pay for things (SPV wallets are just as secure for the sender). If everyone had to download the whole blockchain just to use Bitcoin on the phone then I’m afraid Bitcoin wouldn’t be practical as a payment system at all.&lt;/p&gt;
&lt;p&gt;Despite SPV wallets being quite secure running a full node is presented as a requirement for everyone. Core developer Luke-Jr &lt;a href=&quot;https://www.reddit.com/r/Bitcoin/comments/5ant54/questions_about_running_a_full_node/d9i1zyt/&quot;&gt;doesn’t even consider SPV wallet users “actual users”&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Running a full node makes you an actual Bitcoin user&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://bitcoin.stackexchange.com/questions/52148/should-i-use-a-full-node-as-my-main-wallet&quot;&gt;Here’s Luke-Jr’s response&lt;/a&gt; to the question “Should I use a full node as my main wallet?” on the bitcoin stackexchange:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If you’re not using a full node for your wallet, you’re not using Bitcoin, and won’t get the benefits Bitcoin provides over fiat currency. You might as well be using PayPal in that case, except with a random anonymous person in place of a regulated company…&lt;/p&gt;
&lt;p&gt;So, always use a full node.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That everyone should use a full node is used as an argument against raising the 1MB block size limit because there may be some people somewhere who can’t store or download the data required. Despite this making Bitcoin unable to scale past 7 tx/s and fees of $60 pricing out the very people who have the most difficulty running full nodes.&lt;/p&gt;
&lt;h1&gt;Hard forks &amp;amp; SegWit&lt;/h1&gt;
&lt;p&gt;A common defense in these discussions is “But always prioritizing security over all else is good”. Except it’s not consistently prioritized.&lt;/p&gt;
&lt;p&gt;I bring you the case of SegWit, a solution to the &lt;a href=&quot;https://en.bitcoin.it/wiki/Transaction_malleability&quot; title=&quot;Transaction Malleability&quot;&gt;transaction malleability problem&lt;/a&gt;. Jaqen Hash’ghar wrote a &lt;a href=&quot;https://medium.com/the-publius-letters/segregated-witness-a-fork-too-far-87d6e57a4179&quot; title=&quot;Segregated Witness: A Fork Too Far&quot;&gt;great article (2016)&lt;/a&gt; of the whole ordeal. I recommend it although it’s a bit long.&lt;/p&gt;
&lt;p&gt;To make a long story short SegWit was deployed as a soft fork instead of a hard fork. A hard fork would have been cleaner but it requires all nodes to upgrade and people must agree with the change otherwise the coin would have split into multiple coins (like the Bitcoin and Bitcoin Cash hard fork split). This was deemed extremely unwanted since consensus would be hard to get (maybe there’s some parallels to the black and white security approach but that’s not the point I’m trying to make).&lt;/p&gt;
&lt;p&gt;Instead a soft fork circumvents the problem by allowing nodes to continue working as before except they won’t recognize the new features. This was used to implement SegWit as a hack where non-upgraded nodes will view segwit transactions as anyone-can-spend transactions.&lt;/p&gt;
&lt;p&gt;Peter R gave a good talk of why this is a theoretical security regression (&lt;a href=&quot;https://www.slideshare.net/peter_r/a-segwit-coin-is-not-a-bitcoin&quot;&gt;slides&lt;/a&gt;):&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=VoFb3mcxluY&quot;&gt;https://www.youtube.com/watch?v=VoFb3mcxluY&lt;/a&gt;
&lt;p&gt;This regression was pointed out by others like &lt;a href=&quot;https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-December/012103.html&quot;&gt;Peter Todd&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;In its current form, segregated witnesses makes validationless mining
easier and more profitable than the status quo, particularly as
transaction fees increase in relevance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Granted it’s only a theoretical weakness that probably won’t cause any problems, but it’s a clear example of a binary thought process that in this case doesn’t prioritize security.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;There are many examples where features of Bitcoin are discarded as “insecure” without a nuanced discussion about risks and rewards. This binary thinking is actively harmful and must be called out.&lt;/p&gt;
</content></entry><entry><title>OP_RETURN based tokens are fundamentally flawed</title><id>http://jonashietala.se/blog/2018/07/28/opreturn_based_tokens_are_fundamentally_flawed/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2018/07/28/opreturn_based_tokens_are_fundamentally_flawed" rel="alternate"/><published>2018-07-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Two new Bitcoin Cash token solutions have recently been suggested:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/document/d/1GcDGiVUEa87SIEjrvM9QcCINfoBw-R7EPWzNVR4M8EI/edit&quot;&gt;Simple Ledger Protocol: A token system for Bitcoin Cash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.yours.org/content/introducing-colored-coins--a-bitcoin-cash-token-implementation-faa5cb7308c6&quot;&gt;Introducing Colored Coins: a Bitcoin Cash token implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both are improvements over Tokeda as they allow permissionless transfers. However all commit to &lt;code&gt;OP_RETURN&lt;/code&gt; which unfortunately is fundamentally flawed.&lt;/p&gt;
&lt;h1&gt;No true SPV wallet support&lt;/h1&gt;
&lt;p&gt;Despite claims of being “SPV friendly” true SPV wallets cannot validate the transactions. Instead they need choose between&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced SPV wallet security&lt;/li&gt;
&lt;li&gt;Use light wallet based validation&lt;/li&gt;
&lt;li&gt;Trusted 3rd parties validation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In some combination.
The whole point of SPV is to gain transaction security without trust and without validating the whole (or parts of) the chain. This removes the bases of SPV security in some ways and to be frank calling them “SPV friendly” is disingenuous.&lt;/p&gt;
&lt;p&gt;I am also confused over scaling concerns for on-chain proposals while they’re missing for proposals that suggest turning SPV wallets to light wallets. It’s frankly much, much easier to grow the blocksize and let the few miners and full nodes handle the brunt work than to require SPV wallets to collect, scan or store more data. Functioning SPV wallets is the key to (trustless) scaling in Bitcoin Cash and must be treated as such. Of course we must assume popular tokens may be used proportional to BCH so they have the same scaling requirements.&lt;/p&gt;
&lt;h1&gt;Alternative consensus model&lt;/h1&gt;
&lt;p&gt;Since &lt;code&gt;OP_RETURN&lt;/code&gt; can contain both valid and invalid token transfers full nodes are used to keep track of all tokens. Put in another way instead of miner consensus we have consensus by full nodes. Or as reddit user insette eloquently put it:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;muh full node IS the consensus&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why does it matter? Well what happens when nodes disagree? Naturally this problem is what Bitcoin originally solves with POW, often referred to as Nakamoto Consensus.
For example if there’s a security issue or bug in one wallet/node implementation a silent consensus divergence can occur. Compared to a Bitcoin hard fork this may not be immediately evident.&lt;/p&gt;
&lt;p&gt;How should upgrades be done? What if the issuer wants to reverse some transactions and releases their own &lt;code&gt;OP_RETURN&lt;/code&gt; interpretation implementation? What if this happens to several tokens, how should we follow the consensus of everything at the same time?
If a divergence does happen how can we decide which state is correct? “The issuer decides” isn’t good enough since two users may have had problems trading amongst themselves.&lt;/p&gt;
&lt;p&gt;Not to mention malicious actors who can try to attack the network in various ways. Defrauding users or destabilizing the network is much easier with shaky consensus.&lt;/p&gt;
&lt;h1&gt;Fear of the Hard Fork&lt;/h1&gt;
&lt;p&gt;What is this, 2017? Arguments that a Bitcoin Cash token scheme should avoid consensus changes are exactly like the arguments that brought us SegWit instead of a regular blocksize increase. I thought we were past things like that.&lt;/p&gt;
&lt;p&gt;Yes changes needs to be done carefully but let’s take a step back. We’re talking about foundations for tokens potentially worth a whole lot of money. Great care must be used regardless of solution. Suggesting to rush an off-chain solution because a hard fork one can’t be ready this autumn is disingenuous and irresponsible.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Work on these proposals probably started a while ago and people are understandably reluctant to set them aside, nobody wants their work to be wasted (I don’t believe it is but it may feel like it if it’s not adopted). Yet I think token schemes based on &lt;code&gt;OP_RETURN&lt;/code&gt; is a dead end and we should focus our energy on miner validated and fully SPV capable tokens. Thus far only GROUP fits the bill.&lt;/p&gt;
&lt;p&gt;To once again quote Counterparty contributor insette:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;But I’m just saying, there are technical reasons why OP_RETURN protocols suck, and there are also technical reasons why Ethereum doesn’t suck.&lt;/p&gt;
&lt;/blockquote&gt;</content></entry><entry><title>Top ten activities that make me happy</title><id>http://jonashietala.se/blog/2017/06/24/top_ten_activities_that_make_me_happy/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2017/06/24/top_ten_activities_that_make_me_happy" rel="alternate"/><published>2017-06-24T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Recently we finally moved out of our old apartment and into a new larger apartment and it’s awesome. It’s no more than a year old and feels very fresh compared to the old one. It’s also larger with an extra room, dishwasher (!) and closer to the city centrum and everything is basically better. The move also showed me just how easy it is to collect stuff and things; I had a lot of things hidden away in a small storage room/closet in the old apartment.&lt;/p&gt;
&lt;p&gt;Now I like to buy stuff, I like to collect things and I love the feeling of opening packages and the smell of “new”. But when looking at the amount of forgotten stuff I have you’ve got to wonder: how much happiness do you get from the stuff? And what actually makes you happy?&lt;/p&gt;
&lt;p&gt;This is what I believe (rightfully or wrongly) to be the top ten activities that makes me happy, in no particular order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do stuff with Veronica (walk, talk, …)&lt;/li&gt;
&lt;li&gt;A calm regular evening with Veronica&lt;/li&gt;
&lt;li&gt;Training (currently BJJ and power lifting)&lt;/li&gt;
&lt;li&gt;Play games (boardgames, cardgames or computer games)&lt;/li&gt;
&lt;li&gt;Hang out with friends&lt;/li&gt;
&lt;li&gt;Make things&lt;/li&gt;
&lt;li&gt;Solve problems&lt;/li&gt;
&lt;li&gt;Eat and enjoy good food and drinks&lt;/li&gt;
&lt;li&gt;Read books, manga or other stories&lt;/li&gt;
&lt;li&gt;Watch quality tv series, movies or other videos (includes streams of different kinds)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These activities notably do not require a large amount of stuff or money. Maybe it’s a good idea to prioritize these things instead of collecting more stuff.&lt;/p&gt;
</content></entry><entry><title>Habits to start</title><id>http://jonashietala.se/blog/2017/03/09/habits_to_start/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2017/03/09/habits_to_start" rel="alternate"/><published>2017-03-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I haven’t been feeling quite as forward or as energetic lately. There are no set plans, habits or goals for this spring and I don’t have a clear vision of what to do currently but it also feels… fine? Maybe I will cruise in a lower gear for a while and rev up when my mood changes. In the meanwhile I have habits I’d like to cultivate &lt;em&gt;sometime&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;Daily Habits&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Headspace either on mornings or evenings&lt;/li&gt;
&lt;li&gt;Read a book ~15-min before sleep&lt;/li&gt;
&lt;li&gt;Flashcards with Anki for example&lt;/li&gt;
&lt;li&gt;Listen to talk to me in korean podcast&lt;/li&gt;
&lt;li&gt;Cold shower&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Weekly Habits&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Study BJJ videos/instuctionals&lt;/li&gt;
&lt;li&gt;Study korean (workbooks etc)&lt;/li&gt;
&lt;li&gt;Hobby project a little every weekend&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>(Fake) Bittman Chinese Chicken</title><id>http://jonashietala.se/blog/2017/01/23/fake_bittman_chinese_chicken/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2017/01/23/fake_bittman_chinese_chicken" rel="alternate"/><published>2017-01-23T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Lesson 6! I went to Cervera and bought a holder to allow me to steam chicken.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/4hourchef/steamed_chicken1.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;I broke the recipe on multiple fronts: chicken wings instead of chicken breasts, mushroom soy instead of tamarin, roman salad instead of baby bok choi (where the heck do you find that…) and I even forgot to season with salt and lemon… But the chicken itself turned out really well. Still got a 7 from both me and Veronica.&lt;/p&gt;
&lt;p&gt;Next time I will use actual chicken breasts and I won’t forget the salt. As usual I will include something more, more salad perhaps.&lt;/p&gt;
</content></entry><entry><title>Zucchini Crabcakes</title><id>http://jonashietala.se/blog/2017/01/22/zucchini_crabcakes/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2017/01/22/zucchini_crabcakes" rel="alternate"/><published>2017-01-22T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;With a tiny bit more planning I made a dinner out the lessons 4 and 5 as the crabcakes were only supposed to be an appetizer:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/4hourchef/zucchini_crabcakes.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Crabcakes&lt;/strong&gt;: Surprisingly delicious. Both me and Veronica gives them a 7.&lt;br /&gt;
&lt;strong&gt;Zucchini&lt;/strong&gt;: While I thought they passed Veronica said “Zucchini is not my thing” and promptly gave it a 2. Yikes.&lt;/p&gt;
</content></entry><entry><title>Coconut Cauliflower Curry Mash</title><id>http://jonashietala.se/blog/2017/01/17/coconut_cauliflower_curry_mash/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2017/01/17/coconut_cauliflower_curry_mash" rel="alternate"/><published>2017-01-17T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s time for lesson 3. I made the mistake of not planning for something to augment the mash with, but a simple salad had to do:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/4hourchef/cauliflowers.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;It was okay. Girlfriend gave it 5/10 and I gave it a 6/10, a higher rating would be possible if there was something else to eat it with.&lt;/p&gt;
</content></entry><entry><title>The 4-Hour Chef: Scrambled Eggs</title><id>http://jonashietala.se/blog/2017/01/14/the_4-hour_chef_scrambled_eggs/index.html</id><updated>2023-10-01T13:50:11+00:00</updated><link href="https://www.jonashietala.se/blog/2017/01/14/the_4-hour_chef_scrambled_eggs" rel="alternate"/><published>2017-01-14T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been listening to &lt;a href=&quot;http://fourhourworkweek.com/podcast/&quot; title=&quot;The Tim Feriss Show&quot;&gt;The Tim Ferriss Show&lt;/a&gt; a while now and he and his guests often inspire me to make changes and start doing new things. I got introduced to Josh Waitzkin’s excellent &lt;a href=&quot;http://www.joshwaitzkin.com/the-art-of-learning/&quot; title=&quot;The Art of Learning&quot;&gt;The Art of Learning&lt;/a&gt; and the meta skill of learning has since then fascinated me. So when I got wind of Tim’s book about learning (and coincidentally also about cooking) I managed to get it for Christmas.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fourhourchef.com/&quot; title=&quot;The 4-Hour Chef&quot;&gt;The 4-Hour Chef&lt;/a&gt; contains a framework for learning a new skill fast. Exactly what that entails, or if it even works, I might get into another time. For now I will focus on doing some of the cooking lessons in the book. I will do the basic lessons and then reevaluate if I should continue, if I even make it that far. Anyway he suggests to photograph and document the food you make and so I present to you the Scrambled Eggs I made this morning:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/4hourchef/scrambled_eggs.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;It was actually very good. Seasoned with Onion (should have been garlic!), Cumin and Mint.&lt;/p&gt;
</content></entry><entry><title>2016 in Review</title><id>http://jonashietala.se/blog/2016/12/27/2016_in_review/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2016/12/27/2016_in_review" rel="alternate"/><published>2016-12-27T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;See the &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly reviews&quot;&gt;previous reviews&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;2016 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Placed 2nd in Linköping’s Regional in Netrunner.&lt;/li&gt;
&lt;li&gt;Won a couple of smaller Netrunner tournaments.&lt;/li&gt;
&lt;li&gt;Got Veronica to play &lt;a href=&quot;https://boardgamegeek.com/boardgame/169255/game-thrones-card-game-second-edition&quot; title=&quot;Game of Thrones: The Card Game (second edition)&quot;&gt;Game of Thrones&lt;/a&gt; with us. She beat us and she loved it!&lt;/li&gt;
&lt;li&gt;Programmed a little bit of &lt;a href=&quot;http://elixir-lang.org/&quot; title=&quot;Elixir programming language&quot;&gt;Elixir&lt;/a&gt; and a tiny bit of front end web development.&lt;/li&gt;
&lt;li&gt;Built a &lt;a href=&quot;/blog/2016/10/12/building_the_gh60/&quot; title=&quot;GH60&quot;&gt;custom keyboard&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2016 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Got engaged.&lt;/li&gt;
&lt;li&gt;Achieved 1-Dan in ITF Taekwon-do.&lt;/li&gt;
&lt;li&gt;Started training &lt;a href=&quot;https://en.wikipedia.org/wiki/Brazilian_jiu-jitsu&quot; title=&quot;BJJ&quot;&gt;Brazilian Jiu-Jitsu&lt;/a&gt; with Veronica.&lt;/li&gt;
&lt;li&gt;Got in to the habit of doing powerlifting 2-3 times a week.&lt;/li&gt;
&lt;li&gt;Read &lt;a href=&quot;/blog/2016/12/27/read_books/&quot; title=&quot;2016 Read Books&quot;&gt;8 books and 10 mangas&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Wrote &lt;a href=&quot;/archive&quot; title=&quot;My archive&quot;&gt;10 blog posts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Played a bunch of &lt;a href=&quot;https://boardgamegeek.com/boardgame/30549/pandemic&quot; title=&quot;Pandemic&quot;&gt;Pandemic&lt;/a&gt; with Veronica and others. &lt;em&gt;Very good&lt;/em&gt; co-op boardgame.&lt;/li&gt;
&lt;li&gt;Got other boardgames, among others: &lt;a href=&quot;https://boardgamegeek.com/boardgame/167791/terraforming-mars&quot; title=&quot;Terraforming Mars&quot;&gt;Food Chain Magnate&lt;/a&gt; and &lt;a href=&quot;https://boardgamegeek.com/boardgame/175914/food-chain-magnate&quot; title=&quot;Food Chain Magnate&quot;&gt;Terraforming Mars&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Went to &lt;a href=&quot;https://en.wikipedia.org/wiki/Prague&quot; title=&quot;Prague&quot;&gt;Prague&lt;/a&gt; with Veronica, very nice vacation.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2015 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Didn’t read enough books.&lt;/li&gt;
&lt;li&gt;Practically no hobby programming.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2016&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Take care of Veronica.&lt;/li&gt;
&lt;li&gt;Go on vacation with Veonica, possibly a couple of smaller ones.&lt;/li&gt;
&lt;li&gt;Learn how to cook.&lt;/li&gt;
&lt;li&gt;Learn more korean.&lt;/li&gt;
&lt;li&gt;Train more.&lt;/li&gt;
&lt;li&gt;Prioritize personal develoment.&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>2016 Read Books</title><id>http://jonashietala.se/blog/2016/12/27/read_books/index.html</id><updated>2024-04-29T06:23:18+00:00</updated><link href="https://www.jonashietala.se/blog/2016/12/27/read_books" rel="alternate"/><published>2016-12-27T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Yeah so I managed to not read a single fiction book this year. To compensate and make myself feel better I’ll add in some new mangas I’ve read, but I may may have missed some.&lt;/p&gt;
&lt;h1&gt;Fiction&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Crickets&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;Non-Fiction&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Getting to Yes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relax into Stretch&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thinking, Fast and Slow&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;59 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Hard Thing About Hard Things&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Design of Everyday Things&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Winning Through Intimidation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Programming Phoenix&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Manga&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Death Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Reread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ghost in the Shell&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tokyo Ghoul&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Promised Neverland&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Might be my current favourite? Simply amazing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kingdom&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Reread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Grand Blue&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Onani Master Kurosawa&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Don’t let the title put you off, it’s a surprisingly deep manga.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;One Punch Man&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;My Hero Academia&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tokyo Ghoul&lt;/strong&gt; and &lt;strong&gt;Tokyo Ghoul:re&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>Autumn 2016 Goals Retrospective</title><id>http://jonashietala.se/blog/2016/12/17/autumn_2016_goals_retrospective/index.html</id><updated>2023-10-01T13:48:58+00:00</updated><link href="https://www.jonashietala.se/blog/2016/12/17/autumn_2016_goals_retrospective" rel="alternate"/><published>2016-12-17T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;a href=&quot;/blog/2016/08/12/goals_for_autumn_2016/&quot; title=&quot;Goals for Autumn 2016&quot;&gt;Earlier this year&lt;/a&gt; I set out some goals I wanted to accomplish this autumn. I accomplished a few things and I failed others.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exercise and Health&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Eat more strict LCHF for 1 month &lt;span class=&quot;ok&quot;&gt;ok&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Train BJJ or MMA for 1 month &lt;span class=&quot;ok&quot;&gt;ok&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2 months of lifting at the gym &lt;span class=&quot;ok&quot;&gt;ok&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Powerlifting&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;100 kg deadlift 5x5 &lt;span class=&quot;ok&quot;&gt;ok&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;75 kg bench 5x5 &lt;span class=&quot;failed&quot;&gt;failed&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;85 kg squat 5x5 &lt;span class=&quot;ok&quot;&gt;ok&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Side split with both feet besides the yoga mat   &lt;span class=&quot;failed&quot;&gt;failed&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Hobby Projects&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2016/08/26/a_3x3x3_led_cube/&quot; title=&quot;A Small LED cube&quot;&gt;Build a 3x3 LED cube&lt;/a&gt; &lt;span class=&quot;ok&quot;&gt;ok&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Go through &lt;em&gt;Programming Phoenix&lt;/em&gt; and &lt;em&gt;Programming Elixir&lt;/em&gt; &lt;span class=&quot;partly&quot;&gt;partly&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Construct a &lt;a href=&quot;/blog/2016/10/12/building_the_gh60/&quot; title=&quot;GH60&quot;&gt;custom keyboard&lt;/a&gt; &lt;span class=&quot;ok&quot;&gt;ok&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Create a usable budgeting tool on par with my currently used system &lt;span class=&quot;failed&quot;&gt;failed&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The only habits I successfully started was to take daily D-vitamine supplements and I went to the gym three times a week, on average.&lt;/p&gt;
&lt;h1&gt;Lessons learned&lt;/h1&gt;
&lt;p&gt;While I did accomplish a few things I did not complete them all. I failed the bench press as I overestimated how much I could take, which is understandable as I didn’t really know where my baseline were. In the future I would need to get that before throwing numbers around. I didn’t increase the side split as I never got in the habit of proper stretching, maybe because I wished to but I didn’t really &lt;em&gt;want&lt;/em&gt; to achieve it. The hobby programming again got left behind as I just didn’t have the energy left after work to motivate myself.&lt;/p&gt;
&lt;p&gt;I guess I will try to do something similar next year, but then be more selective of my goals and focus more on the habits, the process, than of the goals themselves. The ones I did accomplish were easier and had a clear path to victory (go train X times).&lt;/p&gt;
&lt;p&gt;As far as the habits go I never outlined a strategy for actually starting them. It goes without saying that I would fail almost all of them. I’m currently trying to start meditating via &lt;a href=&quot;https://www.headspace.com/&quot; title=&quot;Headspace&quot;&gt;Headspace&lt;/a&gt; and the strategy I have now is focus on one goal at a time and when I’ve accomplished it 21 times I consider it ingrained and I can focus on the next one.&lt;/p&gt;
</content></entry><entry><title>Doing some online Personality tests</title><id>http://jonashietala.se/blog/2016/12/11/tests/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2016/12/11/tests" rel="alternate"/><published>2016-12-11T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;For some reason I’ve done a couple of personality tests the last month, mostly to satisfy my own curiosity.&lt;/p&gt;
&lt;h1&gt;The Braverman Test&lt;/h1&gt;
&lt;p&gt;Inspired by &lt;a href=&quot;http://fourhourworkweek.com/2015/07/21/charles-poliquin/&quot;&gt;Charles Poliquin’s visit on The Tim Ferriss Show&lt;/a&gt; I tried out the &lt;a href=&quot;http://advancedpsychcare.tripod.com/sitebuildercontent/sitebuilderfiles/braverman.test.pdf&quot;&gt;Braverman test&lt;/a&gt; to determine my neurotransmitter type. The point Charles makes is that the type of training most suited to you is determined by your neurotransmitter type, which can be found using the Braverman test.&lt;/p&gt;
&lt;p&gt;This is my result:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;  Dominant Nature     Deficiencies
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Dopamine:       28          2
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Acetylcholine:  22          3
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;GABA:           28         11
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Serotonin:      20          8
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I couldn’t find any good references to what the ranges mean but I think it means I have a balanced dominant nature and slight GABA and Serotonin deficiencies. According to &lt;a href=&quot;http://www.theinertia.com/surf/the-five-elements-of-athlete-its-all-about-neurotransmitters/&quot;&gt;this article&lt;/a&gt; I’m an Earth type:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The earth-type athlete has a balanced neurotransmitter profile — they are stable and consistent. These are the guys and gals that show up to the hill every day ready to go. They are well-rounded athletes and thrive on stability, consistency, and routine. They are very sensitive to variations in routine; and if they partied too hard the night prior, you will hear about it and their performance will suffer.&lt;/p&gt;
&lt;p&gt;While earth types can stay on the bike or board for a full season without needing to switch things up, they need to vary intensity and volume in their approach. This means going on longer, mellower rides for a couple weeks and then going on shorter, balls-to-the-wall ventures for a little while, striking a balance that won’t lead them to burn out. Too much intensity and volume at the same time will lead to straight exhaustion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which seems to match my experience well. Going forward I will continue with the same routine focusing on 4 big exercises (squat/bench/chins/deadlift) but I will have a 3-4 week period focusing on volume followed by 3-4 weeks focusing on heavier more intense training.&lt;/p&gt;
&lt;p&gt;What &lt;a href=&quot;https://www.t-nation.com/training/five-elements&quot;&gt;Charles says&lt;/a&gt; about Earth types also rhymes well. Especially the part about cold and sleep:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If you overtrain an Earth person, they’ll come down with a cold. They are generally very particular about the quality and quantity of their sleep. They are the ones who will piss and moan during a squat workout about missing an hour of sleep.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;ADHD&lt;/h1&gt;
&lt;p&gt;My girlfriend Veronica came home one day from work after a seminar about ADHD. At first she was drawing parallels to her students but it ended with her drawing parallels to me. I’ve had this imagine in my mind about a kid with ADHD who can’t control what to say, can never be still and acting out but that’s not necessarily true.&lt;/p&gt;
&lt;p&gt;I tried to fill out &lt;a href=&quot;http://adhd-npf.com/wp-content/uploads/2009/01/18Q-ADHDTest.pdf&quot;&gt;a test&lt;/a&gt; (Swedish) and reading about ADHD online. It seems everything fits really well, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hard to finish tasks.&lt;/li&gt;
&lt;li&gt;Difficulty to remember appointments, meetings and other things. I’m constantly looking for my slippers, keys and other stuff.&lt;/li&gt;
&lt;li&gt;Avoid starting a task requiring a lot of thought. I’m always procrastinating.&lt;/li&gt;
&lt;li&gt;I can’t sit still without touching, poking or working with something. It’s even really hard to watch a TV show (even if I love it) without doing something at the same time. This is a really big problem for me.&lt;/li&gt;
&lt;li&gt;Constantly feeling overactive.&lt;/li&gt;
&lt;li&gt;I’ve always had problems doing careless mistakes, especially when doing “easy” or “boring” tasks.&lt;/li&gt;
&lt;li&gt;Hard to keep concentration on people when they’re speaking.&lt;/li&gt;
&lt;li&gt;I’m sensitive sound, overly so.&lt;/li&gt;
&lt;li&gt;Problems falling to sleep, it’s hard to relax even when I’m tired.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And many other…&lt;/p&gt;
&lt;p&gt;Now it doesn’t really mean anything. It won’t change who I am or anything but it certainly explains a lot about why I do things and why I’m uncomfortable with things others seem to have no problem with. In the end it’s opened my eyes a bit and made me think about what I do more which is great.&lt;/p&gt;
&lt;h1&gt;Asperger&lt;/h1&gt;
&lt;p&gt;After talking about ADHD at work we naturally discussed other disorders like psycopath and asperger. I’m fairly sure I’m not a psycopath, I do feel empathy and remorse and I don’t think I’m especially egoistic nor exhibit overly antisocial behavior, but I may be a bit further on the asperger spectra.&lt;/p&gt;
&lt;p&gt;For fun I tried out an &lt;a href=&quot;http://aspergerstest.net/aq-test/&quot;&gt;aspergers test&lt;/a&gt; and I scored a 28. According to the site that means:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;26-31 gives a borderline indication of an autism spectrum disorder. It is also possible to have aspergers or mild autism within this range.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As I don’t recognize myself, and Veronica agrees, I don’t think I have autism or asperger but I still scored higher than I was expecting.&lt;/p&gt;
</content></entry><entry><title>Building the GH60</title><id>http://jonashietala.se/blog/2016/10/12/building_the_gh60/index.html</id><updated>2026-04-27T11:10:05+00:00</updated><link href="https://www.jonashietala.se/blog/2016/10/12/building_the_gh60" rel="alternate"/><published>2016-10-12T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve finally completed my first custom made keyboard. I’m still missing stabilizers and some smaller screws to hold it all together but I’ve been using it the last days and I thought I’d share.&lt;/p&gt;
&lt;h1&gt;The hardware&lt;/h1&gt;
&lt;p&gt;Several years ago I joined the &lt;a href=&quot;https://geekhack.org/index.php&quot; title=&quot;Geekhack forum&quot;&gt;geekhack forum&lt;/a&gt; and I joined in a few group buys. I ordered some cool keycaps and I also entered the &lt;a href=&quot;https://geekhack.org/index.php?topic=41464.0&quot; title=&quot;GH60 Group Buy&quot;&gt;GH60 Group Buy&lt;/a&gt; which sold plates, stabilizers, PCBs and switches so you can build a more minimalistic keyboard. Unfortunately the group buy crashed and burned and it’s long overdue with the creators vanishing and leaving the group buy with not enough money. I did get my two PCBs and my switches but I’m still waiting for my plates and stabilizers… Which may never arrive.&lt;/p&gt;
&lt;p&gt;I did source a 60% plate from &lt;a href=&quot;https://www.massdrop.com/buy/60-aluminum-plate&quot; title=&quot;Sentraq 60% Keyboard Plate: Massdrop&quot;&gt;massdrop&lt;/a&gt; and I used &lt;a href=&quot;https://deskthority.net/wiki/Cherry_MX_Green&quot; title=&quot;Cherry MX Green&quot;&gt;Cherry MX Green&lt;/a&gt; switches which is a harder clicky cherry variant.&lt;/p&gt;
&lt;h1&gt;Pictures&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/gh60_pink/solder.jpg&quot; width=&quot;400&quot; /&gt;
&lt;figcaption&gt;My beautiful solder job&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/gh60_pink/back.jpg&quot; width=&quot;600&quot; /&gt;
&lt;figcaption&gt;In all it’s glory&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/gh60_pink/sideview.jpg&quot; width=&quot;600&quot; /&gt;
&lt;figcaption&gt;You can see the plate mashed between the switches and the PCB&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/gh60_pink/switches.jpg&quot; width=&quot;600&quot; /&gt;
&lt;figcaption&gt;A full view of the switches from the top&lt;/figcaption&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/gh60_pink/keycaps.jpg&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;The beautiful keycaps&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The white doesn’t shine through at all when you’re at the keybord, the photo isn’t representative.&lt;/p&gt;
&lt;h1&gt;Firmware&lt;/h1&gt;
&lt;p&gt;I tried out both the &lt;a href=&quot;https://github.com/tmk/tmk_keyboard&quot;&gt;tmk_keyboard&lt;/a&gt; and &lt;a href=&quot;https://github.com/jackhumbert/qmk_firmware&quot;&gt;qmk_firmware&lt;/a&gt; for my keyboard. qmk is basically the same as tmk but with extended features (which I don’t think I’m currently using?).&lt;/p&gt;
&lt;p&gt;The code is available on Codeberg: &lt;a href=&quot;https://codeberg.org/treeman/qmk_firmware&quot;&gt;https://codeberg.org/treeman/qmk_firmware&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dependencies:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;dfu-programmer&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;avr-binutils&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;avr-gcc&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;avr-libc&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then to flash the firmware press the reset button on the PCB and do:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;dfu-programmer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; atmega32u4 erase&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;dfu-programmer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; atmega32u4 flash &lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;lt;&lt;/span&gt;gh60_layout.hex&lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;dfu-programmer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; atmega32u4 start&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m currently using a fairly standard qwerty layout and I’ve moved down Escape in place of Caps Lock as I use Vim at a daily basis. I’ve also included a function key which if pressed will allow F1-F12 and arrow keys. Holding down Caps Lock (now Escape) also works as a function key. Holding caps lock works remarkably well, I can see why many Emacs users remap it to Ctrl.&lt;/p&gt;
&lt;p&gt;Then I use the rightmost modifiers, which I’ve never even pressed?, to set up a numpad layer and a mouse layer. The mouse layer doesn’t work well however… Not enough control over the movement sadly.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;C&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight C&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;BASE&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;FUN&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;NUMPAD&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt;&lt;span class=&quot;keyword control import define c&quot;&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;entity name constant preprocessor c&quot;&gt;MOUSE&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta preprocessor macro c&quot;&gt; &lt;span class=&quot;constant numeric c&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;support type stdint c&quot;&gt;uint16_t&lt;/span&gt; PROGMEM keymaps&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;MATRIX_ROWS&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;MATRIX_COLS&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;/*&lt;/span&gt; 0: Default layer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * ,-----------------------------------------------------------.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |  `|  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|BSP|DEL|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  [|  ]|     |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |------------------------------------------------------|    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |Esc/Fn|  A|  S|  D|  F|  G|  H|  J|  K|  L|  ;|  &amp;#39;|  \|Ret |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |Shif|   |  Z|  X|  C|  V|  B|  N|  M|  ,|  .|  /| Fn|Shift |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |Ctrl|Gui |Alt |          Space         |Alt |    |Mous|NPad|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * `-----------------------------------------------------------&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;punctuation definition comment c&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;KEYMAP_HIETALA&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        GRV&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric c&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   MINS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;EQL&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; BSPC&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; DELETE&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TAB&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; Q&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   W&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   E&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   R&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   T&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   Y&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   U&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   I&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   O&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   P&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   LBRC&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;RBRC&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;            \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        FN4&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; A&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   S&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   D&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   F&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   G&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   H&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   J&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   K&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   L&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   SCLN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;QUOT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;BSLS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;ENT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;        \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        LSFT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;NUBS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;Z&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   X&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   C&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   V&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   B&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   N&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   M&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;   COMM&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;DOT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; SLSH&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;FN0&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; RSFT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;       \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        LCTL&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;LGUI&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;LALT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;             SPC&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;                  RALT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;NO&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  FN3&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  FN1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;/*&lt;/span&gt; 1: Function layer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * ,-----------------------------------------------------------.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |Lr0| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|   |   |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |     |   | Up|   |   |   |Hom|PgD|PgU|End|PgU|   |   |     |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |------------------------------------------------------|    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |      |Lef|Dow|Rig|   |   |Lef|Dow|Up |Rig|PgD|   |   |    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |    |   |   |   |   |   |   |Hom|PgD|PgU|End|   |   |      |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |    |    |    |                        |    |    |    |    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * `-----------------------------------------------------------&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;punctuation definition comment c&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;KEYMAP_HIETALA&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        FN2&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;F1&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F2&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F3&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F4&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F5&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F6&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F7&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F8&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F9&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  F10&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; F11&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; F12&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PGDN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;UP&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  PGUP&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;HOME&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PGDN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PGUP&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;END &lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PGUP&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;           \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;LEFT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;DOWN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;RGHT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;LEFT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;DOWN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;UP  &lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;RGHT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PGDN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;      \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;HOME&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PGDN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PGUP&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;END &lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;      \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;               TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;               TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;/*&lt;/span&gt; 2: Numpad
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * ,-----------------------------------------------------------.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |Lr0|   |   |   |   |   |   |   |  *|  *|  *|  -|  +|   |   |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |     |   |   |   |   |   |  -|  7|  8|  9|  +|  +|   |     |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |------------------------------------------------------|    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |      |   |   |   |   |   |  .|  4|  5|  6|  ,|  ,|  /|    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |    |   |   |   |   |   |   |  0|  1|  2|  3|  .|   |KP Ent|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |    |    |    |                        |NLCK|    |    |    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * `-----------------------------------------------------------&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;punctuation definition comment c&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;KEYMAP_HIETALA&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        FN2&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PAST&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PAST&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PAST&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PMNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PPLS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;P7  &lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;P8&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  P9&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  PPLS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PPLS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;           \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PDOT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;P4  &lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;P5&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  P6&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  COMM&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;COMM&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PSLS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;      \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;P0  &lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;P1&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  P2&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  P3&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;  PDOT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;PENT&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;      \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;               TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;               NLCK&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment block c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;/*&lt;/span&gt; 3: Mouse mode
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * ,-----------------------------------------------------------.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |Lr0|   |   |   |   |   |   |   |   |   |   |   |   |   |   |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |     |   |MUp|   |   |   |   |   |   |   |   |   |   |     |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |------------------------------------------------------|    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |      |MLe|MDn|MRh|   |   |MLe|MDn|MUp|MRg|   |   |   |Bt1 |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |    |   |   |   |   |   |   |ScL|ScD|ScU|ScR|   |   |  Bt2 |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |-----------------------------------------------------------|
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * |    |    |    |          Bt1           |    |    |    |    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     * `-----------------------------------------------------------&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     &lt;span class=&quot;punctuation definition comment c&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;KEYMAP_HIETALA&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        FN2 &lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_U&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;            \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_L&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_D&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_R&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_L&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_D&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_U&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;MS_R&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;BTN1&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;        \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;WH_L&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;WH_D&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;WH_U&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;WH_R&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;BTN2&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;       \
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;               BTN1&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;               TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;TRNS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier c&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;support type stdint c&quot;&gt;uint16_t&lt;/span&gt; PROGMEM fn_actions&lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta block c&quot;&gt;&lt;span class=&quot;punctuation section block begin c&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ACTION_LAYER_TAP_TOGGLE&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;FUN&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Fn momentary or toggling.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric c&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ACTION_LAYER_TOGGLE&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;NUMPAD&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Toggle numpad.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric c&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ACTION_LAYER_SET&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;constant numeric c&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; ON_BOTH&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Back to base layer, safety escape.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric c&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ACTION_LAYER_TOGGLE&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;MOUSE&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; Toggle mouse layer.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta brackets c&quot;&gt;&lt;span class=&quot;punctuation section brackets begin c&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric c&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section brackets end c&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator assignment c&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;variable function c&quot;&gt;ACTION_LAYER_TAP&lt;/span&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group begin c&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;FUN&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; KC_ESC&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call c&quot;&gt;&lt;span class=&quot;meta group c&quot;&gt;&lt;span class=&quot;punctuation section group end c&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator c&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-slash c&quot;&gt;&lt;span class=&quot;punctuation definition comment c&quot;&gt;//&lt;/span&gt; On hold trigger Fn overlay. On tap act as esc.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section block end c&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Naturally things will change but this is what I’m rolling with for now.&lt;/p&gt;
</content></entry><entry><title>Weekend Tournaments</title><id>http://jonashietala.se/blog/2016/09/06/weekend_tournaments/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2016/09/06/weekend_tournaments" rel="alternate"/><published>2016-09-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This weekend was filled by playing cards. On Saturday I hosted a small Game of Thrones tournament and on Sunday the local Netrunner community hosted a small summer kit tournament.&lt;/p&gt;
&lt;h1&gt;Game of Thrones&lt;/h1&gt;
&lt;p&gt;We’ve had a similar tournament once before when me and my girlfriend invited two of our friends and had a small 4 person tournament. The last time I was the only one with any cards and I had made 4 decks which we then drafted. Quite surprising to us my girlfriend Veronica the tournament and even admitted it was a fun experience. This time one of our friends Filip and I had practiced a bit and we even went to a regionals before while Veronica hadn’t played at all since the last tournament and the other friend barely knew the rules.&lt;/p&gt;
&lt;p&gt;The tournament was a success and we had a good time. I managed to eek out a win against Filip but extremely surprisingly Veronica managed to beat us all once again. I’m still in shock and I’m still not sure how it all happened… &lt;em&gt;Again&lt;/em&gt;. But I’m very proud of her of course! And this time she exclaimed how &lt;em&gt;fun&lt;/em&gt; it all was, several times during the day! I’m sure it was fun &lt;a href=&quot;http://thronesdb.com/card/01044&quot; title=&quot;Tears of Lys&quot;&gt;killing&lt;/a&gt;, &lt;a href=&quot;http://thronesdb.com/card/01176&quot; title=&quot;Dracarys&quot;&gt;burning&lt;/a&gt; and &lt;a href=&quot;http://thronesdb.com/card/02093&quot; title=&quot;Mirri Maz Duur&quot;&gt;killing us some more&lt;/a&gt;…&lt;/p&gt;
&lt;h1&gt;Netrunner&lt;/h1&gt;
&lt;p&gt;Before this tournament I and after my &lt;a href=&quot;/blog/2016/03/31/recent_experiences_with_netrunner_tournaments/&quot; title=&quot;Latest netrunner tournament report&quot;&gt;latest tournament report&lt;/a&gt; I actually had two more tournaments; the regionals in Linköping and the ANRPC finals I qualified for. I was going to and actually stated a writeup but I was kind of tired of card gaming in general at that time. I simply had played too much. In the regionals I just barely made the cut and somehow ended up 2nd. For the ANRPC finals I did the classic error of taking two completely new decks and predictably crashed and burned. I did log the &lt;a href=&quot;https://netrunnerdb.com/en/decklist/34866/making-some-noise-link-ping-regionals-2nd-8th-after-swiss&quot; title=&quot;Regionals runner&quot;&gt;runner&lt;/a&gt; and &lt;a href=&quot;https://netrunnerdb.com/en/decklist/34865/northern-sol-link-ping-regionals-2nd-8th-after-swiss-&quot; title=&quot;Regionals corp&quot;&gt;corp&lt;/a&gt; decks for the regionals but didn’t for ANRPC, they were a classic Dumblefork and some sort of rush Argus.&lt;/p&gt;
&lt;p&gt;This small 6 person tournament was the perfect thing for me to reinvigorate my interest in netrunner. I had a great time.&lt;/p&gt;
&lt;p&gt;With MWL destroying the runner love of my life and with asset spam being rampant I was forced to choose a new runner. CtM punished me hard on jinteki.net so I decided to &lt;a href=&quot;https://netrunnerdb.com/en/decklist/37537/derivative-fork-link-ping-summer-kit-1st-&quot; title=&quot;Runner deck&quot;&gt;pack the hate&lt;/a&gt;. I was very close to choosing a killing corp but I decided to try to &lt;a href=&quot;https://netrunnerdb.com/en/decklist/37536/all-hail-our-new-sol-overlords-link-ping-summer-kit-1st-&quot; title=&quot;Corp deck&quot;&gt;change my corp deck&lt;/a&gt; which went quite well during the regionals.&lt;/p&gt;
&lt;p&gt;I did a ton of mistakes when I played and especially my corp wasn’t feeling all too great but somehow I managed to win the tournament! We also streamed the games I think 3 out of my 5 games got streamed. They should be uploaded to Youtube in time.&lt;/p&gt;
</content></entry><entry><title>A small LED Cube</title><id>http://jonashietala.se/blog/2016/08/26/a_3x3x3_led_cube/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2016/08/26/a_3x3x3_led_cube" rel="alternate"/><published>2016-08-26T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;As a follow up of my &lt;a href=&quot;/blog/2016/08/12/goals_for_autumn_2016/&quot;&gt;hobby project goals&lt;/a&gt; this autumn I have now completed the smallest goal there. I got started a little with soldering by constructing a small 3x3x3 LED cube.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/small_led_cube.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Although extremely hard to see in this picture it actually worked without a hitch! It’s not the prettiest job ever but it was quite meditative to work with actually. Now I’m just waiting for the plate to arrive so I can start working on my keyboard.&lt;/p&gt;
&lt;p&gt;Oh and the reward for accomplishing this subgoal was to go to black belt academy, a Taekwon-do training camp last week. I like the idea of having clear goals and rewards to work against.&lt;/p&gt;
</content></entry><entry><title>Goals for Autumn 2016</title><id>http://jonashietala.se/blog/2016/08/12/goals_for_autumn_2016/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2016/08/12/goals_for_autumn_2016" rel="alternate"/><published>2016-08-12T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Every once and a while I like to redo my priorities and set new goals for myself.&lt;/p&gt;
&lt;p&gt;I recently read the book &lt;a href=&quot;https://richardwiseman.wordpress.com/books/59-seconds-think-a-little-change-a-lot/&quot; title=&quot;59 seconds&quot;&gt;59 seconds&lt;/a&gt; which among other things presented a way of structuring goals I will try out. In short you should divide your main goal into 5 subgoals with a date of completion, a reward upon completion and you should specify why and how you can accomplish it. You should describe the main goal and also list the benefits for completing the goal and for best effect you should also go public with your goals.&lt;/p&gt;
&lt;h1&gt;Exercise and Health&lt;/h1&gt;
&lt;p&gt;The goal is get stronger, get more energy and in general get a more healthy lifestyle.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Eat more strict LCHF for 1 month&lt;/p&gt;
&lt;p&gt;I can achieve this because I’ve done it before. The problems are when there are unhealthy snacks available but focusing on how bad I feel after giving in. Focusing on better alternatives like dark chocolate, wine or various meet will help.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Aug 28&lt;br /&gt;
The reward will be: Massage&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Train BJJ or MMA for 1 month&lt;/p&gt;
&lt;p&gt;Me and my girlfriend are planning to try out BJJ together. If she likes it continuing with it should be easy for me to continue training. If not I will continue with either BJJ or MMA as I’m pretty hyped to explore some other martial arts styles which hopefully will offset the potential motivation problem.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Oct 2&lt;br /&gt;
The reward will be: Gi or training gear&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2 months of lifting at the gym&lt;/p&gt;
&lt;p&gt;I will go to the gym 3 times a week during lunch and buy salad next door for lunch and I will train for ~45 min. It’s something I’ve done before and I felt good about it. The biggest problem here is to get in the habit and after that it should run smoothly.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Oct 30&lt;br /&gt;
The reward will be: New training shorts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;100 kg deadlift 5x5, 75 kg bench 5x5, 85 kg squat 5x5&lt;/p&gt;
&lt;p&gt;I have reached comparable results before and with dedicated training I should be able to go beyond previous results. By getting in the habit of going to the gym reaching these weights and reps should be straightforward. One problem is that I might be planning to train too much but by not training to failure but for more energy and focusing more on consistency should alleviate that issue. Another one is that my grip is very weak after the injury but even before that. It can be combated with the grip trainer at work.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Nov 27&lt;br /&gt;
The reward will be: &lt;em&gt;undecided&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Side split with both feet besides the yoga mat&lt;/p&gt;
&lt;p&gt;I’ve had a problem with my groin for who knows how many years and it’s time toget a routine to combat it. The theory I have now is that I’ve been far too eager and I’ve started training too hard too fast. By focusing less on the high kicks in Taekwon-do and training other styles more and by not pushing myself during the stretching sessions the pain should recede slowly. The plan is to use limbering or very light stretching every day and once a week focus solely on stretching. Here again the issue is to get in the habit but I would &lt;em&gt;really&lt;/em&gt; love to be able to train fully without pain. The goal is just a slight increase in flexibility which I’m using to get a concrete goal to aim for.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Dec 25&lt;br /&gt;
The reward will be: &lt;em&gt;undecided&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Benefits&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Happier about myself.&lt;/li&gt;
&lt;li&gt;More energy in my life.&lt;/li&gt;
&lt;li&gt;Remove the dissatisfaction I’ve had the last years about not having exercised enough.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Hobby Projects&lt;/h1&gt;
&lt;p&gt;The goal is to get going with some hobby projects.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Build a 3x3 LED cube.&lt;/p&gt;
&lt;p&gt;The goal is to get started with soldering. Should be a small project and an hour here or there should be enough to see it through.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Aug 10&lt;br /&gt;
The reward will be: Taekwon-do training camp&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go through &lt;em&gt;Programming Phoenix&lt;/em&gt; and &lt;em&gt;Programming Elixir&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I think I want to learn more about web development and I’ve heard a ton of good stuff about Phoenix and Elixir. I’ve had a lot of problems completing sideprojects before but going through books hasn’t been that big of an issue.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Sep 15&lt;br /&gt;
The reward will be: New wallet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Construct a custom keyboard&lt;/p&gt;
&lt;p&gt;Too long have I had two GH60 PCB and a bunch of keycaps lying around. I’m still missing a plate but with that (and possibly stabilizers) I have all that it takes to finalize it. The soldering and the assembly shouldn’t be too though and a custom keyboard is something I’ve wanted for a long time. I’ve had problems finishing side projects but if I get all parts I should be able to at least start the project. With it started and with all parts on my desk I should be forced to finish it.&lt;/p&gt;
&lt;p&gt;This will be achieved by: Nov 30&lt;br /&gt;
The reward will be: Netrunner world championship decks&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a usable budgeting tool on par with my currently used system&lt;/p&gt;
&lt;p&gt;I’ve been using a fairly crap spreadsheet to track my expenses and loosely track my investments into cryptocurrencies and I had an idea to create a website to track them and to budget for the upcoming months. It serves a practical use but it’s also an excuse for me to learn Phoenix, Elixir and general web development. That’s a fairly powerful motivator but it may not be enough. By making it an explicit goal and a deadline hopefully I will finish this one. The danger here is that the deadline is too far away and that I don’t prioritize the project.&lt;/p&gt;
&lt;p&gt;This will be achieved by:  Dec 20&lt;br /&gt;
The reward wil be: Extra investment in cryptocurrencies&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Benefits&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Expanded knowledge is good both for my profession and to satisfy my own curiosity.&lt;/li&gt;
&lt;li&gt;The satisfaction of completing projects and creating things is wonderful.&lt;/li&gt;
&lt;li&gt;I’ve been wanting a custom made keyboard for a long time.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Habits to start&lt;/h1&gt;
&lt;p&gt;I’ve been using &lt;a href=&quot;https://habitica.com/&quot; title=&quot;Habitica&quot;&gt;Habitica&lt;/a&gt; (previously HabitRPG) to help establish habits and it’s been working wonderfully well for me when I’ve used it. For a couple of months I’ve had a break from it but I will try to use it again to try to establish a few habits.&lt;/p&gt;
&lt;h2&gt;Daily habits&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Exploratory limbering once a day&lt;/li&gt;
&lt;li&gt;Cold shower once a day&lt;/li&gt;
&lt;li&gt;Grip strength every day at work&lt;/li&gt;
&lt;li&gt;Read a book 15 min every day (before sleep)&lt;/li&gt;
&lt;li&gt;Anki flashcards every day (occassional refill)&lt;/li&gt;
&lt;li&gt;Take D-vitamin supplements&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Weekly habits&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Gym 3x a week&lt;/li&gt;
&lt;li&gt;Martial arts (BJJ/MMA) 2x a week&lt;/li&gt;
&lt;li&gt;Isometric stretch once a week&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>Slackware installation notes</title><id>http://jonashietala.se/blog/2016/07/29/slackware_installation_notes/index.html</id><updated>2026-04-27T11:10:20+00:00</updated><link href="https://www.jonashietala.se/blog/2016/07/29/slackware_installation_notes" rel="alternate"/><published>2016-07-29T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It seems like it’s been a &lt;a href=&quot;/blog/2015/08/02/slackware_update/&quot; title=&quot;Slackware update 2015&quot;&gt;yearly&lt;/a&gt; &lt;a href=&quot;/blog/2014/07/05/reinstalling_slackware/&quot; title=&quot;Slackware update 2014&quot;&gt;recurrence&lt;/a&gt; reinstalling slackware from scratch. This time it happened during my vacation when I was mucking around with trying to compile erlang with wxWidgets support and somehow a make clean started to remove / and I only noticed it too late… Not sure how it happened but I had changed things in the make and config files. Oh well no data lost just annoyances.&lt;/p&gt;
&lt;p&gt;This process was done with Slackware 14.2 and roughly details what I’ve done so I can retrace my steps in the future.&lt;/p&gt;
&lt;h1&gt;Up and running&lt;/h1&gt;
&lt;h2&gt;Booting&lt;/h2&gt;
&lt;p&gt;Even with only a laptop with windows installed hope is not lost. The almighty alien has a &lt;a href=&quot;http://alien.slackbook.org/blog/welcome-windows-user/&quot; title=&quot;Create usb boot loader from windows&quot;&gt;great tutorial&lt;/a&gt; creating an usb boot loader from windows. At first I tried to extract the contents of usbboot.img using &lt;a href=&quot;https://www.izarc.org/&quot; title=&quot;IZarc&quot;&gt;IZarc&lt;/a&gt; but it reported it as empty but &lt;a href=&quot;http://www.winimage.com/winimage.htm&quot; title=&quot;Winimage&quot;&gt;Winimage&lt;/a&gt; worked fine. The rest went smoothly.&lt;/p&gt;
&lt;h2&gt;Partitions&lt;/h2&gt;
&lt;p&gt;I used a split of &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/usr/local/&lt;/code&gt;, &lt;code&gt;/home&lt;/code&gt;. The partitions on my laptop looks messy as I’ve kept some factory windows partitions.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; df&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;h&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;Filesystem&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;      Size  Used Avail Use&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; Mounted on&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/dev/root&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;        50G   27G   21G  57&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;devtmpfs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;        2.9G     0  2.9G   0&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /dev&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;tmpfs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;           2.9G  1.1M  2.9G   1&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /run&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;tmpfs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;           2.9G  688K  2.9G   1&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /dev/shm&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cgroup_root&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;     2.9G     0  2.9G   0&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /sys/fs/cgroup&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/dev/sda5&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;        50G   93M   47G   1&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /usr/local&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/dev/sda7&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;       148G  2.0G  139G   2&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /home&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/dev/sda2&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;       187G   88G   99G  48&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /mnt/win&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cgmfs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;           100K     0  100K   0&lt;span class=&quot;meta group expansion job shell&quot;&gt;&lt;span class=&quot;punctuation definition variable job shell&quot;&gt;%&lt;/span&gt;&lt;/span&gt; /run/cgmanager/fs&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Wireless&lt;/h2&gt;
&lt;p&gt;Can be found in &lt;code&gt;/extra/wicd&lt;/code&gt; in the slackware release.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;installpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; ...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;chmod&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; +x /etc/rc.d/rc.wicd&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/etc/rc.d/rc/wicd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; start&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;wicd-curses&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;sbopkg/slackpkg&lt;/h2&gt;
&lt;p&gt;Use slackpkg to update official Slackware packages.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;slackpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; update&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;slackpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; update gpg&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The vast majority of packages I install can be found on &lt;a href=&quot;https://slackbuilds.org/&quot; title=&quot;Slackbuilds&quot;&gt;Slackbuilds&lt;/a&gt;. Many unnamed dependencies can simply be found here. &lt;a href=&quot;http://www.sbopkg.org/&quot; title=&quot;sbopkg&quot;&gt;sbopkg&lt;/a&gt; makes it a lot easier to use.&lt;/p&gt;
&lt;h1&gt;Environment&lt;/h1&gt;
&lt;p&gt;To quickly get up and running use xfce and &lt;code&gt;startx&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Both &lt;code&gt;fish&lt;/code&gt; and &lt;code&gt;neovim&lt;/code&gt; can be installed from slackbuilds. Make sure to set fish as login shell as well as the default shell for both root and user.&lt;/p&gt;
&lt;h2&gt;dotfiles&lt;/h2&gt;
&lt;p&gt;Store &lt;a href=&quot;https://github.com/treeman/dotfiles&quot;&gt;https://github.com/treeman/dotfiles&lt;/a&gt; in &lt;code&gt;~/dotfiles&lt;/code&gt; and symlink from there as needed.&lt;/p&gt;
&lt;h2&gt;Xmonad&lt;/h2&gt;
&lt;p&gt;Install &lt;code&gt;ghc&lt;/code&gt; and &lt;code&gt;cabal-install&lt;/code&gt; from slackbuilds and then use cabal to install the rest:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install cabal-install&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install xmonad&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install xmonad-contrib&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Use sbopkg to install conky (make sure to manually include lua support) and nitrogen.&lt;/p&gt;
&lt;p&gt;Clone &lt;a href=&quot;https://github.com/robm/dzen&quot;&gt;https://github.com/robm/dzen&lt;/a&gt; and edit &lt;code&gt;config.mk&lt;/code&gt;, choose option 7 (XPM, XFT, Xinerama). I’m not 100% I need to do it for the laptop or if this only was needed to support Xinerama but I did it this way anyway.&lt;/p&gt;
&lt;p&gt;When started use &lt;code&gt;lxappearance&lt;/code&gt; to set a prettier look for firefox and other gui.  See &lt;a href=&quot;/blog/2014/07/05/reinstalling_slackware/#Fonts&quot; title=&quot;Prettify fonts&quot;&gt;previous post&lt;/a&gt; about prettifying fonts.&lt;/p&gt;
&lt;h1&gt;Dev&lt;/h1&gt;
&lt;h2&gt;Perl&lt;/h2&gt;
&lt;p&gt;Use cpan as root whenever missing packages are found:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install CPAN&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install Modern::Perl&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install DateTime&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Blog&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;blog&lt;/a&gt; uses Hakyll.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install missingH&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install hakyll&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also setup &lt;code&gt;~/.s3cfg&lt;/code&gt; to allow syncing.&lt;/p&gt;
&lt;h2&gt;Phoenix&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Download the erlang-otp slackbuild and &lt;a href=&quot;http://erlang.org/download/&quot;&gt;find the latest version&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;a href=&quot;https://github.com/elixir-lang/elixir/releases/&quot;&gt;latest Elixir&lt;/a&gt; from source.&lt;/li&gt;
&lt;li&gt;Follow the &lt;a href=&quot;http://www.phoenixframework.org/docs/installation&quot;&gt;installation guide&lt;/a&gt; and install the dependencies.&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>Long Term Goals Update</title><id>http://jonashietala.se/blog/2016/07/18/long_term_goals_update/index.html</id><updated>2023-10-01T08:35:05+00:00</updated><link href="https://www.jonashietala.se/blog/2016/07/18/long_term_goals_update" rel="alternate"/><published>2016-07-18T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;During my vacation I suddenly got a bunch of “life crisis” type thoughts in an almost panic inducing intensity. They were mostly thoughts about not having accomplished anything and that the future looks bleak and meaningless and it’s not worth to do anything. As usual they are mostly illogical and they usually subside fairly quickly. But they got me thinking of what I want to do with my life and what some of my larger goals are. Making &lt;a href=&quot;/blog/tags/yearly_review/&quot; title=&quot;Yearly Review&quot;&gt;yearly reviews&lt;/a&gt; is a great way of combating the “I haven’t done anything” thoughts.&lt;/p&gt;
&lt;p&gt;I’ve written about some &lt;a href=&quot;/blog/2013/02/16/long_term_goals/&quot; title=&quot;My Long Term Goals part 1&quot;&gt;long term&lt;/a&gt; &lt;a href=&quot;/blog/2013/02/16/long_term_goals_part_2/&quot; title=&quot;My Long Term Goals part 2&quot;&gt;goals&lt;/a&gt; before. Let’s revisit them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;I want to have kids&lt;/strong&gt; &lt;em&gt;(No change)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Still the most important long-term goal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write a Book&lt;/strong&gt; &lt;em&gt;(No change)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Having written a book feels like a big accomplishment I’d like to have on my list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Contribute to a popular open-source project&lt;/strong&gt; &lt;em&gt;(Completed)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I made some contributions to &lt;a href=&quot;http://www.rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; in 2014.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Black belt in Taekwon-do&lt;/strong&gt; &lt;em&gt;(Completed)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yes! I achieved 1-Dan this June.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write my own Programming Language&lt;/strong&gt; &lt;em&gt;(Abandoned)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It would be cool to write my own programming language, but in the grand scheme of things this doesn’t feel as important. I’m just not motivated enough to start up it as a big project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Own a Snooker table&lt;/strong&gt; &lt;em&gt;(Abandoned)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Looking back this looks like a fairly stupid materialistic goal. Snooker is awesome but does it really warrant being one of my long term life goals? Not a chance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One can argue about the definition of a long term goal vs a short term goal. Generally it’s something I wish to have on my list of stuff I’ve done during my life.&lt;/p&gt;
&lt;p&gt;I would also like to add two new goals I’ve been thinking about lately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Learn a new language&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And I don’t mean another programming language, maybe Korean or Finnish.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Freedom over my work/life balance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I think this is a big point for me. I value freedom very highly and I see no bigger gain than to have control over your work.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I should do is to expand on my goals and think about why I want them and &lt;em&gt;how&lt;/em&gt; I should accomplish them. For now though this quick overview is enough to calm down my anxious thoughts.&lt;/p&gt;
</content></entry><entry><title>Recent experiences with Netrunner tournaments</title><id>http://jonashietala.se/blog/2016/03/31/recent_experiences_with_netrunner_tournaments/index.html</id><updated>2024-04-29T06:23:18+00:00</updated><link href="https://www.jonashietala.se/blog/2016/03/31/recent_experiences_with_netrunner_tournaments" rel="alternate"/><published>2016-03-31T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After a bit of a hiatus after the &lt;a href=&quot;/blog/2016/01/16/netrunner_winter_kit_tournament/&quot; title=&quot;Netrunner Winter Kit Tournament 16th Jan&quot;&gt;Winter Kit Tournament&lt;/a&gt; the 16th January I participated in three tournaments during February - March. After each of these tournaments I started a writeup of them but they fell off my mind a bit but consider this my break with my blogging hiatus.&lt;/p&gt;
&lt;h1&gt;Store Championship Örebro&lt;/h1&gt;
&lt;p&gt;After more than a month with no Netrunner I was stoked and in high spirits as we went to the friendly meta of Örebro the 20th Feb. I decided to try out two of the currently most popular decks: &lt;a href=&quot;http://netrunnerdb.com/en/decklist/31948/bootcamp-glacier-is-here-to-stay&quot; title=&quot;bootcamp glacier is here to stay&quot;&gt;bootcamp glacier is here to stay&lt;/a&gt; and &lt;a href=&quot;http://netrunnerdb.com/en/decklist/31636/the-2-armed-ice-feast-1st-place-undefeated-mead-hall-store&quot; title=&quot;The 2-Armed Ice Feast&quot;&gt;The 2-Armed Ice Feast&lt;/a&gt; (sometimes called Dumblefork) and I don’t think I made any changes to the decks at all. I’ve always liked Blue Sun so I was excited to try a competitive variant and I loved the “Looking 4 Job” variants of Whizzard before.&lt;/p&gt;
&lt;p&gt;On to the games. We were only 8 people and I was matched up against Niclas who used practically the same decks as I did. I was quite nervous as he’s pretty awesome and he basically smashed me in both games. The second game I faced a relatively new players where I won the games comfortably and the third I lost two fairly close games against Peder’s MaxX and NEH FA (he did play better though). The last games I won another close Whizzard game but lost my corp game due &lt;a href=&quot;http://netrunnerdb.com/en/card/09030&quot; title=&quot;Apocalypse&quot;&gt;Apocalypse&lt;/a&gt; (From Nasir!) catching me with my pants down.&lt;/p&gt;
&lt;p&gt;I found out the hard way that the bootcamp glacier wasn’t the easiest to pilot (as suggested in the comments) and the dumblefork deck didn’t play the same as the previous Whizzard decks I’v played. Serves me right playing new decks on a tournament.&lt;/p&gt;
&lt;p&gt;In the end I finished second to last, officially my worst tournament placement, and I must admit I was quite disappointed. I’d like to think I don’t care about loosing, but I think that’s wrong, I very much want to win and I do play Netrunner competitively when I do go to these tournaments. Another thing which made my disappointment a lot worse was that I missed out on the wonderful &lt;a href=&quot;https://www.fantasyflightgames.com/en/news/2015/10/2/2016-android-netrunner-store-championships/&quot; title=&quot;2016 Netrunner Store Championships&quot;&gt;Leela Playmat&lt;/a&gt;. Maybe I’ll get another shot at it during the Store Champ in Linköping but for that I should probably do myself a favor and prepare a bit.&lt;/p&gt;
&lt;p&gt;But I did get 3 copies of our lord and saviour &lt;a href=&quot;http://netrunnerdb.com/en/card/04015&quot; title=&quot;Jackson Howard&quot;&gt;Jackson Howard&lt;/a&gt;!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/orebro_sc160220.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;h1&gt;ANRPC Qualifier Örebro&lt;/h1&gt;
&lt;p&gt;Only a week later we went to yet another tournament in Örebro. This time it was a player organized tournament where the top 3 qualified for a finals tournament in Stockholm but there were a ton of other things to win as well.&lt;/p&gt;
&lt;p&gt;As this seemed to a quite competitive event with players coming in from Stockholm and the surrounding area and considering my poor performance from last week I had lowered my expectations a lot. I had set my sights on simply not getting crushed and as long as I put up a good fight I’d be happy.&lt;/p&gt;
&lt;p&gt;As the decks the previous work out for me (I can hardly fault the decks) I decided to go back to my &lt;a href=&quot;http://netrunnerdb.com/en/decklist/32444/making-some-noise-anrpc-rebro-qualifier-1st-&quot; title=&quot;Making Some Noise (ANRPC Örebro Qualifier 1st) &quot;&gt;Noise build&lt;/a&gt; which has served me well before. The tweaks I did to the build after the most wanted list was simply to cut a clone chip and the shards. I decided to throw in a Trope as an attempt to prevent running out of cards. During the day it was only useful once and as of this writing I’m leaning more towards &lt;a href=&quot;http://netrunnerdb.com/en/decklist/33405/bigboy-noise&quot; title=&quot;BigBoy Noise&quot;&gt;BigBoy Noise&lt;/a&gt; with Levy/Peddler/Inject. I complained a bit (half jokingly) about missing the kill from my corp deck during the previous weekend and I got inspired by the &lt;a href=&quot;http://netrunnerdb.com/en/decklist/30767/canadian-graveyard-shl-jinteki-edition-1st-&quot; title=&quot;Canadian Graveyard (SHL Jinteki Edition 1st)&quot;&gt;Canadian Graveyard&lt;/a&gt; deck d1en used to win stimhack league with. I &lt;a href=&quot;http://netrunnerdb.com/en/decklist/32445/to-the-grave-anrpc-rebro-qualifier-1st-&quot; title=&quot;To The Grave (ANRPC Örebro Qualifier 1st)&quot;&gt;made some tweaks&lt;/a&gt; using other shells and I was good to go!&lt;/p&gt;
&lt;p&gt;During this week I also tried out &lt;a href=&quot;http://www.jinteki.net/&quot;&gt;http://www.jinteki.net/&lt;/a&gt; which is an unofficial online version of the game. There has been other clients (OCTGN) but I’ve always been reluctant to use them as I didn’t want to spend too much time playing… Well that’s done and I’m caught now. The interface is quite good if you already know the game and I used to practice with the decks a little bit and they seemed to perform ok.&lt;/p&gt;
&lt;p&gt;I also got my friend Filip to come to his first tournament this weekend after we played a couple of games to refresh the rules during the week. I’m still pretty impressed as he basically agreed to come even without knowing the game basically at all. I gave him a standard Foodcoats list (minus global food, no dupes) and a vamp Jesminder. Sadly he didn’t win any games but the opposition was tough and he didn’t go to time and he said he had fun (apparently as he has now bought a core and some expansions!).&lt;/p&gt;
&lt;h2&gt;The Games&lt;/h2&gt;
&lt;p&gt;After the tournament I made some notes about the games I played but they aren’t super exhaustive and it’s been a while since they happened, but here’s a quick summary at least. There were 5 rounds without a cut and some of my games were streamed (but I haven’t seen them uploaded yet).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Round 1&lt;/strong&gt; Got a bye. Sigh. Sure I want to win but I want to play (and win) more… At least Frida (who didn’t participate) played a game with me to ease my pain, thank you! I also think my prospective opponent arrived just as we was starting our round, but I got the bye anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Round 2&lt;/strong&gt; As I had apparently won my first round I got to face fellow Linköping player Harald and on stream for the first time! I distinctly remember looking at my shaking hands at the beginning of the games. Turns out I get nervous playing Netrunner on stream, scared of making mistakes and dumb plays. These games I didn’t mess up too badly as I managed to kill the too passive runner with the combo Hiro/Neural/Ronin and as Noise I got a good start against his NEH fast advance allowing me to close out the game.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Round 3&lt;/strong&gt; Played against a Chaos Theory who siphoned me down, won the psychich field psi game (dodging the kill) and checked all my advances/unadvanced cards. I was too greedy installing a Hiro after the runner clearly checked everything. Noise has a pretty good matchup against RP and he did get a pretty good setup, but so did I and I sat back and milled challenging the remote during advance (caprice foiled me) but I stole enough from R&amp;amp;D and archives to win shortly after.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Round 4&lt;/strong&gt; Second game on stream and I faced another accomplished player. I got a great start as IG against his Whizzard and I managed to keep up my assets and my money. I started to score out as he was a bit too passive but I ended the game with my new favourite combo Hiro/Neural/Ronin dodging the I’ve Had Worse. Then I faced EtF, my most dreaded opposition against Noise. After he made an opening remote I ran it, clicked through the Turing and trashed(!) the Adonis. Then I tried out my luck with Medium but no such avail and after that he rushed me out. In retrospect I handled the game very poorly… I’d like to watch the video whenever it’s available but hopefully it’s not too cringeworthy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Round 5&lt;/strong&gt; Still on the top table and my third streamed game I faced off against another player I know is very good. This time it was my turn to play against a Noise with my IG, which was a first. I don’t really remember the game (need videos!) but I think he got a lot of accesses and I remember feeling he &lt;em&gt;should&lt;/em&gt; have seen enough to win the game. We even checked the deck if I had enough agendas in there (most hidden in R&amp;amp;D) but alas I got the win by running him out of cards. Then I faced another NEH FA. I think I got a good start with some medium action and I got clot online but he managed to claw back. At the end of the game a small crowd had assembled as we slowly went to time. During my turn I milled, checked archives (up to 5 points) and made a last ditch attempt at HQ and finding the 1/5 chance for victory. Two from my view intense games and I’m looking forward to the video, if not to see the games from the other perspective.&lt;/p&gt;
&lt;p&gt;Somehow I managed to win the tournament and apparently I’m going to play in the Stockholm finals, which is great because it means more Netrunner! I still feel like I don’t deserve it as I got an unnecessary bye the first round… The guy who got punished for coming late actually came in 3rd in the end, which is pretty baller, and it makes me feel a little bit better at least.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/anrpc_060227.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;h1&gt;Winter Kit tournament in Linköping&lt;/h1&gt;
&lt;p&gt;Originally planned to be a store championship but as the dates collided with other store champs in the area we couldn’t get enough players we moved it forward. As it happens I had bought a winter kit so we used it as prize support for a 7 people tournament Mars 12th.&lt;/p&gt;
&lt;p&gt;Filip didn’t get enough of netrunner the last time but the decks I provided didn’t really fit his aggressive play style. So I gave him a modified &lt;a href=&quot;http://netrunnerdb.com/en/decklist/28358/apocalypse-now-fury-road-6-2-worlds-2nd-icebreaker&quot; title=&quot;Apocalypse Now / Fury Road - 6-2 Worlds, 2nd Icebreaker&quot;&gt;Fury Road&lt;/a&gt; deck (which is also a variation of what d1en used) an all out Blue Sun Kill deck (Government Takeover/Punitive/Cerebral/Janus/Scorch/) to better fit his playstyle. We also play tested them a little before the tournament.&lt;/p&gt;
&lt;p&gt;I was planning to bring my standard Noise and a fast advance Order of Sol deck to the Store Championship as a bit more competitive decks, but after the tournament was changed to a winter kit tournament I opted to try out something else. &lt;a href=&quot;http://netrunnerdb.com/en/decklist/32970/pitchfork-link-ping-winter-kit-1st&quot; title=&quot;Pitchfork (Linköping Winter Kit 1st)&quot;&gt;Pitchfork&lt;/a&gt; is a cool deck and I don’t play that much Shaper so it seemed like a good idea to try it out (modification to allow Filip to get his Fury Road deck). A couple of months ago I tried a slightly janky/stupid/awesome &lt;a href=&quot;http://netrunnerdb.com/en/decklist/32969/fugu-link-ping-winter-kit-tournament-1st&quot; title=&quot;Biotech kill Linköping Winter Kit 1st)&quot;&gt;Biotech kill&lt;/a&gt; deck I had lots of great fun with so it was time to play some fun jank!&lt;/p&gt;
&lt;p&gt;This time I got another of my friends, Erik, to come to his first tournament. Some time ago I convinced him to buy a core set and he put it to use during the tournament and he said it was more fun than he was expecting!&lt;/p&gt;
&lt;p&gt;I don’t have any notes from this tournament but there were a few moments that stood out. “Why do you play THAT card” when I flipped a Data Mine and in general heads were shaken that day which was great fun. The best thing was a turn 2 corp win against andromeda who made dirty laundry on psychic field on the 3rd click… and I won the psi (&lt;em&gt;always&lt;/em&gt; choose The Brewery). I played Filip and he played great, he even got a Government Takeover scored as I was too afraid to run it (I still won though) and as runner he keyholed me to death and won that game.&lt;/p&gt;
&lt;p&gt;In the end the game I lost against Filip was the only game I lost and so won my second winter kit tournament and I got my Corroder alt art. Erik also won two games so hopefully he has also seen the light and will return to our next tournament.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/winter_kit160312.jpg&quot; /&gt;
&lt;/figure&gt;</content></entry><entry><title>Netrunner Winter Kit Tournament Linköping</title><id>http://jonashietala.se/blog/2016/01/16/netrunner_winter_kit_tournament/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2016/01/16/netrunner_winter_kit_tournament" rel="alternate"/><published>2016-01-16T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After quite the hiatus from &lt;a href=&quot;/blog/tags/netrunner/&quot; title=&quot;Netrunner&quot;&gt;Netrunner&lt;/a&gt; I had a chance to join a tournament here in Linköping with 14 participants. The number of players has grown a lot since the previous tournament which is really great.&lt;/p&gt;
&lt;p&gt;As I really wanted to win the wonderful &lt;a href=&quot;http://www.inprnt.com/gallery/m_zeilinger/android-day-job/&quot; title=&quot;Day Job&quot;&gt;Day Job&lt;/a&gt; playmat I went with two of the best decks I could come up with. I went with the &lt;a href=&quot;http://netrunnerdb.com/en/decklist/30749/making-some-noise-link-ping-winter-kit-tournament-1st-&quot; title=&quot;Noise decklist&quot;&gt;Noise&lt;/a&gt; deck I’ve been playing a while which has been performing really well. I was expecting a lot of EtF so I was on the verge on playing a classic &lt;a href=&quot;http://netrunnerdb.com/en/decklist/29474/you-re-a-wooley-harry-1st-anrpc-hac&quot; title=&quot;You&amp;#39;re a Wooley Harry&quot;&gt;Looking 4 Job&lt;/a&gt; Whizzard deck but I switched to Noise just before the tournament as I’m more comfortable with it but I also find it more fun to play Noise than anything else. As for the corp I had played a little &lt;a href=&quot;http://netrunnerdb.com/en/decklist/30750/world-class-etf-link-ping-winter-kit-tournament-1st-&quot; title=&quot;EtF decklist&quot;&gt;Foodcoats&lt;/a&gt; since it dominated worlds and it has felt extremely solid overall.&lt;/p&gt;
&lt;h1&gt;Tournament structure&lt;/h1&gt;
&lt;p&gt;We did 4 rounds of swiss without a cut, even though I was personally hoping for 5 rounds. The more games I can play the better it is, I just love to play you know. As usual you get 2 points for each game you win and 1 point for a timed win.&lt;/p&gt;
&lt;h2&gt;Round 1: Dan, Reina/Sync&lt;/h2&gt;
&lt;p&gt;vs Reina&lt;/p&gt;
&lt;p&gt;He got me low on credits early but I played it slow and slowly but steadily accumulated enough credits to build rez enough ice and score out. Foodcoats destroyed the game.&lt;/p&gt;
&lt;p&gt;vs Sync&lt;/p&gt;
&lt;p&gt;I was really scared of Sync as Noise is weak against tags and I don’t run any meat damage protection. But I got a nice start and got a few points lead but he still managed to score out some astro counters and I carelessly gave him a Quantum Predictive Model so he got up to 5 point. Luckily I had set up the shard combo with utopia and hades shard I maged to score out with them the click before he would have won.&lt;/p&gt;
&lt;p&gt;Generally I need to be more mindful of quantum predictive model. I actually think it’s a really good agenda in this type of deck.&lt;/p&gt;
&lt;p&gt;4 points, 2-0&lt;/p&gt;
&lt;h2&gt;Round 2: Johannes, Leela/Haarpsichord&lt;/h2&gt;
&lt;p&gt;vs Leela&lt;/p&gt;
&lt;p&gt;I was really, really poor in the beginning of the game and I had trouble getting my campaigns to stick. I made the really big mistake of trying to rush out an Accelerated Beta Test but I was too poor and too scared of Legwork and The Maker’s Eye after bounce to do it. In the process I had blocked Breaker Bay Grid from my campaigns which made the game really slow… I think I could have won in the end anyway but he got through my remote twice by forcing through an Ichi. Well played by him but I feel like I should have done better.&lt;/p&gt;
&lt;p&gt;vs Haarpsichord&lt;/p&gt;
&lt;p&gt;A bit rushed on time and super scared of 24/7 News Cycle I got a fairly good grip in the beginning with a Lamprey lock and I stole a couple of agendas early. Unfortunately I accumulated two News Team and nullified my lead. I still managed to find a couple of agendas to have the lead.&lt;/p&gt;
&lt;p&gt;In the turn I went through a Gutenberg and took a tag (which I could have avoided with Faust) and gave him a Quantum Predictive Model while I was on 4 points. If I had just broken the sub I would have gone up to 5 points and I had a Hades Shard with at least one 2 pointer in the archive… Once again I need to be more mindful of taking tags. Still had more points and got the timed win.&lt;/p&gt;
&lt;p&gt;5 points, 3-1&lt;/p&gt;
&lt;h2&gt;Round 3: Henrik, Noise/Blue Sun&lt;/h2&gt;
&lt;p&gt;vs Noise&lt;/p&gt;
&lt;p&gt;Etf got set up well and the runner didn’t do anything useful at the start and I got set up really well economically and I was quite safe. Game ended early due to a faceplant into Assassin with only 2 cards in hand and I had a ton of money.&lt;/p&gt;
&lt;p&gt;vs Blue Sun&lt;/p&gt;
&lt;p&gt;I knew Henrik ran an Accelerated Diagnostics combo deck and I was again scared of dying to Scorched Earth with my not having any protection. But I got a lot of HQ and R&amp;amp;D accesses by trashing two Spiderwebs and an Assassin and I managed to ping away some kill pieces. He drew a lot with jacksson and managed to end up with all three copies of scorch in archives and I finally won by a Medium for his whole R&amp;amp;D.&lt;/p&gt;
&lt;p&gt;9 points, 5-1&lt;/p&gt;
&lt;h2&gt;Round 4: Fredrik, Kate/EtF&lt;/h2&gt;
&lt;p&gt;The last game of the tournament and I and Fredrik were the top dogs. As I had one timed win but Fredrik did not so I had to win both games to win the tournament. Tough task as Fredrik is a very solid player.&lt;/p&gt;
&lt;p&gt;vs Kate&lt;/p&gt;
&lt;p&gt;I was a little flooded in the beginning but I didn’t get punished for it and after that I drew really good. I managed to stick the campaigns in the remote and I had a ton of money basically the whole game. Fredrik security nexus kate and I managed to get two 2-points early and I didn’t draw any agendas in the midgame when he was set up with his monster rig.&lt;/p&gt;
&lt;p&gt;At the end of the game I had built up a 4-Ice remote and a 5-Ice R&amp;amp;D. He hit me with an Escher which felt quite awful as he had a bunch of R&amp;amp;D interfaces but it turns out my super taxing ice and R&amp;amp;D luck saved me. Foodcoat can and will make extremely taxing servers it turns out…&lt;/p&gt;
&lt;p&gt;vs EtF&lt;/p&gt;
&lt;p&gt;Fredrik ran a sort of Team Sponsorship fast-advance/rush EtF which I wasn’t looking forward to all that much. But luckily he didn’t draw a lot of economy and I managed to keep him down economically by a combination of lamprey and forcing him to rez ice. I also sniped an early 2-pointer by clicking through an eli and breaking a marcus with Faust, which felt really good admittedly. Overall I managed to keep up a ton of pressure on him even though I didn’t find aesop’s until fairly late.&lt;/p&gt;
&lt;p&gt;I really felt in control the whole game and the game ended as a timed win for me. The only bigger mistake I recall is one I did on my last turn in the game where I installed a cache and then ran on the remote server thinking I could beat the ash trace just to plant into a Turing. At this point I was already at 5 points and what I could have done is walk through R&amp;amp;D 2 times by taking assassin to the face to maximize my chances of getting a regular win.&lt;/p&gt;
&lt;p&gt;12 points, 7-1&lt;/p&gt;
&lt;h1&gt;The results&lt;/h1&gt;
&lt;p&gt;I was a bit down after loosing points in the second round but I managed to recoup very well in the end. I felt I had some really good in some key matches and my decks served me very well. I will probably try some other corps but I may still continue playing Noise even after the most wanted list.&lt;/p&gt;
&lt;p&gt;In the end I managed to win the whole tournament which I didn’t really expect. I was hoping to do well but I wasn’t expecting it.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/netrunner-winter-kit-results.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;As my prize I naturally chose Day Job. The Ice Wall participation prize was great as well. I’m a little sad I didn’t get the Corroder one as I think it looks really good, but you can’t get everything in this world.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/day-job-playmat.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Was a good tournament and everyone were once again awesome! I’m already planning for the next one!&lt;/p&gt;
</content></entry><entry><title>2015 in Review</title><id>http://jonashietala.se/blog/2016/01/01/2015_in_review/index.html</id><updated>2026-04-27T11:10:03+00:00</updated><link href="https://www.jonashietala.se/blog/2016/01/01/2015_in_review" rel="alternate"/><published>2016-01-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Previous reviews: &lt;a href=&quot;/blog/2011/01/06/2010_in_review/&quot; title=&quot;2010 in Review&quot;&gt;2010&lt;/a&gt;, &lt;a href=&quot;/blog/2012/01/04/2011_in_review/&quot; title=&quot;2011 in Review&quot;&gt;2011&lt;/a&gt;, &lt;a href=&quot;/blog/2012/12/31/2012_in_review/&quot; title=&quot;2012 in Review&quot;&gt;2012&lt;/a&gt;, &lt;a href=&quot;/blog/2014/01/04/2013_in_review/&quot; title=&quot;2013 in Review&quot;&gt;2013&lt;/a&gt; and &lt;a href=&quot;/blog/2014/12/31/2014_in_review/&quot; title=&quot;2014 in Review&quot;&gt;2014&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;2015 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Finished my university studies and got a Master in Computer Science.&lt;/li&gt;
&lt;li&gt;Discovered a new boardgame love: &lt;a href=&quot;https://boardgamegeek.com/boardgame/124742/android-netrunner&quot; title=&quot;Android: Netrunner&quot;&gt;Android Netrunner&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Finished top 4 in my first Netrunner Store Championship.&lt;/li&gt;
&lt;li&gt;Won a &lt;a href=&quot;/blog/2015/09/18/netrunner_summer_tournament_linkping/&quot; title=&quot;A local Netrunner tournament report&quot;&gt;small local Netrunner tournament&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Completed my &lt;a href=&quot;/masters_thesis/&quot; title=&quot;My Master&amp;#39;s thesis&quot;&gt;master thesis&lt;/a&gt; about recommender systems.&lt;/li&gt;
&lt;li&gt;Participated in the 48 hour game making competition &lt;a href=&quot;http://ludumdare.com/compo/&quot; title=&quot;Ludum Dare&quot;&gt;Ludum Dare 33&lt;/a&gt; with &lt;a href=&quot;/blog/2015/08/23/xgroar/&quot; title=&quot;Groar, my entry for Ludum Dare 33&quot;&gt;Groar&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Actually styled &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot; title=&quot;Source for this site&quot;&gt;this website&lt;/a&gt; a little bit.&lt;/li&gt;
&lt;li&gt;Achieved 12-kyu at &lt;a href=&quot;https://online-go.com/play&quot; title=&quot;online-go&quot;&gt;online-go&lt;/a&gt; in &lt;a href=&quot;http://en.wikipedia.org/wiki/Go_%28game%29&quot; title=&quot;Go&quot;&gt;Go&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2015 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Took the kids to TKD competitions.&lt;/li&gt;
&lt;li&gt;Achieved 1-Kup in Taekwon-do.&lt;/li&gt;
&lt;li&gt;Started working at &lt;a href=&quot;http://www.configura.com/&quot; title=&quot;Configura&quot;&gt;Configura&lt;/a&gt; where I spend my time doing systems programming in their homegrown language &lt;em&gt;CM&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Read &lt;a href=&quot;/blog/2016/01/01/2015_read_books/&quot; title=&quot;2015 Read Books&quot;&gt;9 books&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Wrote &lt;a href=&quot;/archive&quot; title=&quot;My archive&quot;&gt;26 blog posts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Played a bit of &lt;a href=&quot;https://boardgamegeek.com/boardgame/169255/game-thrones-card-game-second-edition&quot; title=&quot;A Game of Thrones: The Card Game (second edition)&quot;&gt;A Game of Thrones: The Card Game (second edition)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Got new boardgames: &lt;a href=&quot;https://boardgamegeek.com/boardgame/148949/istanbul&quot; title=&quot;Istanbul&quot;&gt;Istanbul&lt;/a&gt; (very good), &lt;a href=&quot;https://boardgamegeek.com/boardgame/26566/homesteaders&quot; title=&quot;Homesteaders&quot;&gt;Homesteaders&lt;/a&gt; (really underrated) and &lt;a href=&quot;https://boardgamegeek.com/boardgame/159508/aquasphere&quot; title=&quot;Aquasphere&quot;&gt;Aquasphere&lt;/a&gt; (quite ok).&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2015 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Read far too few books.&lt;/li&gt;
&lt;li&gt;Did not build my custom keyboard.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2016&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Take care of Veronica.&lt;/li&gt;
&lt;li&gt;Achieve 1-Dan in Taekwon-do.&lt;/li&gt;
&lt;li&gt;Construct a custom keyboard.&lt;/li&gt;
&lt;li&gt;Read more books.&lt;/li&gt;
&lt;li&gt;Play more card games.&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>2015 Read Books</title><id>http://jonashietala.se/blog/2016/01/01/2015_read_books/index.html</id><updated>2023-10-01T13:40:01+00:00</updated><link href="https://www.jonashietala.se/blog/2016/01/01/2015_read_books" rel="alternate"/><published>2016-01-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I didn’t read a lot of books in 2015, but the books I did read were pretty damn good.&lt;/p&gt;
&lt;h1&gt;Fiction&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Song of Ice and Fire: A Dance with Dragons&lt;/strong&gt; - George R.R. Martin&lt;/p&gt;
&lt;p&gt;Reread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Knight of the Seven Kingdoms&lt;/strong&gt; - Gearge R.R. Martin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Skin Collector&lt;/strong&gt; - Jeffery Deaver&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Served Cold&lt;/strong&gt; - Joe Abercrombie&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Heroes&lt;/strong&gt; - Joe Abercrombie&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Red Country&lt;/strong&gt; - Joe Abercrombie&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Non-Fiction&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lessons In The Fundamentals Of Go&lt;/strong&gt; - Kageyama Toshiro&lt;/p&gt;
&lt;p&gt;A great Go book for beginners. Pretty though but very good.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Richest Man in Babylon&lt;/strong&gt; - George S. Clason&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Money: Master the Game&lt;/strong&gt; - Tony Robbins&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>Establishing Habits with Habitica</title><id>http://jonashietala.se/blog/2015/11/21/establishing_habits_with_habitica/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/11/21/establishing_habits_with_habitica" rel="alternate"/><published>2015-11-21T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I have used &lt;a href=&quot;https://habitica.com/&quot; title=&quot;Habitica RPG for your Life&quot;&gt;Habitica&lt;/a&gt; the last 18 months to organize my habits and things I want to get done. I believe it all started with an amazing book called &lt;a href=&quot;http://charlesduhigg.com/the-power-of-habit/&quot; title=&quot;The Power of Habit&quot;&gt;The Power of Habit&lt;/a&gt; which describes the amazing benefits habits can give, both in the context of your own life but also in business. The argument is that habits is the basis for success in whatever area you might be interested in. For me exercise and finishing school were the big driving factors. Even though I was fairly unmotivated with school the last year I managed to get in the habit of regular study and I also used &lt;a href=&quot;https://habitica.com/&quot; title=&quot;Habitica RPG for your Life&quot;&gt;Habitica&lt;/a&gt; as my TODO list which basically pulled me through the writing of writing my master’s thesis.&lt;/p&gt;
&lt;p&gt;After I finished school and started working at &lt;a href=&quot;http://configura.com/&quot; title=&quot;Configura&quot;&gt;Configura&lt;/a&gt; I’ve sadly been neglecting &lt;a href=&quot;https://habitica.com/&quot; title=&quot;Habitica RPG for your Life&quot;&gt;Habitica&lt;/a&gt; a little bit. I still used it every day but a lot less ambitiously than previously, it basically turned into checking off the few still relevant dailies. But I’m now feeling motivated again so I’ve collected new habits I want to do and I’m using Habitica to help me achieve it.&lt;/p&gt;
&lt;p&gt;Habitica is an RPG game where you level up after you complete habits, dailies or To-Dos. The idea is to do real life actions and log them in the game to collect gold, pets and levels. It’s a simple idea and it doesn’t sound like much, but for me the added goals has made it lot more effective than simply writing in a notebook or similar.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/habitica/overview.png&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;With the gold you collect you can buy better gear or buy custom rewards. My idea here is to add things I want to buy or things I want to do there but I haven’t really used it as much before so I’m not sure how effective it’ll be.&lt;/p&gt;
&lt;p&gt;I’m a serial procrastinator and a technique I’ve used with some success is to have some items on my To-Do list which looks important but really aren’t. When I procrastinate I actually try really hard not to do something even to the point that I do &lt;em&gt;other&lt;/em&gt; things instead! So these important looking items acts as honey pots for the procrastination. For example the item “Register .bit domains” has a perceived importance cause I want to have one and I really should get one soon… But in reality it’s no hurry as they are not useful in the general sense and I can easily postpone it a month or even a year or two.&lt;/p&gt;
&lt;p&gt;In the general I’ve gotten a lot of usage out of the To-Do list but in practice you could accomplish the same with pen and paper. The more interesting parts are “Habits” and “Dailies”. They both refer to real-life habits but dailies in Habitica are things you’re supposed to do every day, or on a set of days in the week, and habits are items with positive or negative interactions.&lt;/p&gt;
&lt;p&gt;These were the main focus of my reorganization and to further the immersion factor I used &lt;a href=&quot;http://habitica.wikia.com/wiki/Emoji&quot; title=&quot;Habitica Emoji&quot;&gt;emoji&lt;/a&gt; and I renamed them to be more RPG like so for example “Take D-Vitamins” became “Health Stims” and “Read” became “Lore”.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/habitica/habits_dailies.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;My main focus has always been on the dailies, I never click habits regularly. But adding a habit as a daily with the intent of doing it every day is a really effective way of making sure I complete it regularly. The risk is of course that you mark it as completed anyway, but luckily I only do it very rarely. As you get both a boost and an additional “Perfect Day” stat I feel very incentivized to complete all my dailies. You also get a streak counter for each daily and I feel &lt;em&gt;really&lt;/em&gt; bad about breaking a big streak.&lt;/p&gt;
&lt;p&gt;What follows is a rundown on some of the habits I’m trying cultivate:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I’m trying out the &lt;a href=&quot;http://www.wimhofmethod.com/&quot; title=&quot;The Wim Hof Method&quot;&gt;Wim Hof Method&lt;/a&gt; which I found through a &lt;a href=&quot;http://fourhourworkweek.com/2015/09/07/the-iceman-wim-hof/&quot; title=&quot;Podcast with The Iceman&quot;&gt;podcast&lt;/a&gt;. I basically do a set of breathing exercises every morning and I also do some stretches in the morning.&lt;/li&gt;
&lt;li&gt;As I’m very stiff I want to try to do isometric stretches a couple of times a week.&lt;/li&gt;
&lt;li&gt;I recently started following &lt;a href=&quot;http://www.talktomeinkorean.com/&quot; title=&quot;Talk To Me in Korean&quot;&gt;Talk To Me in Korean&lt;/a&gt; as I want to learn Korean. I use it conjunction with Anki a flashcard program for spaced repetition. The habit I want to establish is to practice a little bit every day.&lt;/li&gt;
&lt;li&gt;As I love to read but I’m also very bad at making time for it I’m trying to make it a habit to read 15 minutes before I go to sleep.&lt;/li&gt;
&lt;li&gt;Brushing my teeth and taking D-vitamins are perfect things to add. I’ve been pretty good at doing it and I’ve had a couple of months long streak of doing them but sadly I’ve forgotten to report it to the site so the streak has been broken…&lt;/li&gt;
&lt;li&gt;I listened to a &lt;a href=&quot;http://fourhourworkweek.com/2015/01/15/pavel-tsatsouline/&quot; title=&quot;Podcast with Pavel Tsatsouline&quot;&gt;podcast with Pavel Tsatsouline&lt;/a&gt; just yesterday and it got me really inspired for going to the gym. I will try to follow the &lt;a href=&quot;http://fourhourworkweek.com/2008/12/18/pavel-8020-powerlifting-and-how-to-add-110-pounds-to-your-lifts/&quot; title=&quot;80/20 Powerlifting routine&quot;&gt;80/20 Powerlifting routine&lt;/a&gt;:&lt;br /&gt;
Only do 3 exercises; deadlift, squats and bench. Always 5 sets with 5 repetitions.&lt;br /&gt;
Tuesday:   Heavy squats&lt;br /&gt;
Thursday:  Heavy bench, light squats&lt;br /&gt;
Saturday:  Heavy deadlift, light bench&lt;br /&gt;
The original program had another component: Competition. I’m not sure if I want to do that though…&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now this is just the general idea. I’m well aware that this may crash and burn but if I successfully do at least half of these things (historically I’m well above that) I consider it a huge accomplishment for me.&lt;/p&gt;
</content></entry><entry><title>Stereotypes</title><id>http://jonashietala.se/blog/2015/10/14/stereotypes/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/10/14/stereotypes" rel="alternate"/><published>2015-10-14T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I read a &lt;a href=&quot;http://ferd.ca/the-little-printf.html&quot; title=&quot;The Little Printf&quot;&gt;great essay or article&lt;/a&gt; about stereotypical programmers called &lt;a href=&quot;http://ferd.ca/the-little-printf.html&quot; title=&quot;The Little Printf&quot;&gt;The Little Printf&lt;/a&gt;. I really couldn’t do it justice so do yourself a favor and go read it. It touches on several types of programmers or rather traits of programmers I recognize in my surroundings and also sadly a bit in myself.  I can especially relate to the programmer who’s always chasing the new hot technology or the one who’s collecting cool but unread programming books, although I’m not doing it for the street cred.&lt;/p&gt;
&lt;p&gt;And then there’s the e-sport fan who watches other play game instead of playing them and again I’m guilty.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/Watching-someone-else-play-a-game-is-a-complete-waste-of-time-comic.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;a href=&quot;http://www.loadingartist.com/&quot;&gt;http://www.loadingartist.com/&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Netrunner Summer Tournament Linköping</title><id>http://jonashietala.se/blog/2015/09/18/netrunner_summer_tournament_linkping/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/09/18/netrunner_summer_tournament_linkping" rel="alternate"/><published>2015-09-18T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;There was another &lt;a href=&quot;/blog/tags/netrunner/&quot; title=&quot;Netrunner&quot;&gt;Netrunner&lt;/a&gt; tournament this Sunday with 8 entrants. We had two new legal data packs with Old Hollywood and The Universe of Tomorrow so a lot of new things were tried. I heard a rumor that a full playset of both Aesop’s Pawnshop and Wyldside were available so I decided to not take my jankiest ideas and play &lt;a href=&quot;http://netrunnerdb.com/en/decklist/26258/the-original-hacker-link-ping-summer-kit-tournament-1st-&quot; title=&quot;Noise decklist&quot;&gt;Noise&lt;/a&gt; and &lt;a href=&quot;http://netrunnerdb.com/en/decklist/26259/renovating-the-future-link-ping-summer-kit-tournament-1st-&quot; title=&quot;Blue Sun decklist&quot;&gt;Blue Sun&lt;/a&gt;. &lt;a href=&quot;http://netrunnerdb.com/en/decklist/26258/the-original-hacker-link-ping-summer-kit-tournament-1st-&quot; title=&quot;Noise decklist&quot;&gt;The Noise build&lt;/a&gt; was practically unchanged from what I’ve played previously. The Blue Sun was a new glacier build with space ice and the new agendas Hollywood Renovation and The Future is Now. I wanted the threat of scorch and I also threw in two snares for extra spice.&lt;/p&gt;
&lt;h1&gt;Swiss&lt;/h1&gt;
&lt;p&gt;With 8 players we did 4 rounds of swiss, without any cut.&lt;/p&gt;
&lt;h2&gt;Match 1: Dan, Valencia/Haarpsichord&lt;/h2&gt;
&lt;p&gt;vs Valencia&lt;/p&gt;
&lt;p&gt;I tried to push a Hollywood Renovation early, but it was snagged with blackmail.  It was a big gamble which unfortunately didn’t pan out.  This was a kinda large mistake, but in the end it didn’t matter.  I got my huge ice up and running and I forced him out of my servers.  I made a big play with Hollywood Renovation where I fast advanced a The Future is Now with the 5th and 6th advancement tokens and the game was basically over from that point.  I think I flatlined him in the end, but that’s more of a symbolic victory as I could have just as easily scored out.&lt;/p&gt;
&lt;p&gt;vs Haarpsichord&lt;/p&gt;
&lt;p&gt;Super close, he had scored a lot of points and I was sitting with clot. In the end he installs 3 new remotes, one behind an ice. I push through the ice to steal the first agenda and I imp the second one (now the Imp is without counters). So I install another program, trashing the imp, then trashing the third remote with the imp. All new remotes were agendas. After this my victory was clear as a run on archives sealed the deal.&lt;/p&gt;
&lt;p&gt;4 points, 2-0&lt;/p&gt;
&lt;h2&gt;Match 2: Harald, Haarpsichord, Haylee&lt;/h2&gt;
&lt;p&gt;vs Haarpsichord&lt;/p&gt;
&lt;p&gt;I felt like I was behind the whole game, but so did Harald. In the end I managed to snag another very close win, but I’m not sure how that happened. All my Aesop’s were in the bottom of my stack but somehow I managed to steal/imp enough to make up for it. What decided things was a Clot hidden on my street peddler, which he overlooked. Without it I should have lost the game.&lt;/p&gt;
&lt;p&gt;vs Haylee&lt;/p&gt;
&lt;p&gt;I allowed some accesses to R&amp;amp;D, but mostly no big damage was done. Then I sealed the game up and the win was basically clear. I had a public support ticking down but we ran out of time so I got one point for being up to 6 agenda points. Maybe I could have played it faster to get the victory on time, but I don’t know.&lt;/p&gt;
&lt;p&gt;7 points, 4-0&lt;/p&gt;
&lt;h2&gt;Match 3: Henrik, NEH, Chaos Theory&lt;/h2&gt;
&lt;p&gt;vs NEH&lt;/p&gt;
&lt;p&gt;I got set up fairly well and I managed to trash a sansan early. I had clot and everything was going alright. I hit a Snare in a remote which took me off guard a bit. The turn after he made another remote and I contemplated running on it, I did have imp tokens after all, but I decided it was fine to possibly allow him a single agenda. Big mistake as I installed cards down to 3 cards in hand and I died to a breaking news and scorch. For some reason I was convinced he was running the fast advance version, or some kind of nearpad, but the reality is I played too fast and didn’t consider everything properly. Live (or die) and learn I guess.&lt;/p&gt;
&lt;p&gt;vs Chaos Theory&lt;/p&gt;
&lt;p&gt;After I rezzed an Archer on the remote it was basically game over as he couldn’t break it with the exception of datasuckers/parasiters, which quickly got used. I iced up my centrals with huge space ice and I could simply score out and win. He tried a big Vamp play against HQ, but on the last click and with a tag he died against double scorch after taking down my curtain wall.&lt;/p&gt;
&lt;p&gt;9 points, 5-1&lt;/p&gt;
&lt;h2&gt;Match 4: Johannes, Haarpsichord/Ian&lt;/h2&gt;
&lt;p&gt;vs Haarpsichord&lt;/p&gt;
&lt;p&gt;A blistering game where he rushed out agendas and I tried to punish/steal with Imp. The game slowed down when I had a Clot on board and I pushed up to 6 points. A run on archives with a Jackson reshuffle and then triggering Utopia shard sealed the deal.&lt;/p&gt;
&lt;p&gt;vs Ian&lt;/p&gt;
&lt;p&gt;We laughed about our decks being super late game focused and he stayed true to his words and he installed a ton of resources, three Gang Signs and two HQ interfaces. I was kinda agenda flooded but I managed to push them out in Archives with double Jackson. The game was decided in a funny way I think, even if I misplayed it quite a bit (I blame tiredness or something!).&lt;/p&gt;
&lt;p&gt;I had Hollywood Renovation with a bunch of advancement tokens, The Future is Now in a naked remote and one Snare and one Scorch in my hand. So I advanced Hollywood Renovation 3 times and scored it. He hit a Snare but nothing else with all his accesses. Then I scored The Future is Now and fetched my second Snare from R&amp;amp;D, which he accessed and died to. Naturally the correct play would have been to advance Hollywood Renovation twice, score The Future is Now and fetch the Snare. Now if he hits a Snare I can just scorch him on my last click.&lt;/p&gt;
&lt;p&gt;13 points, 7-1&lt;/p&gt;
&lt;h1&gt;The results&lt;/h1&gt;
&lt;p&gt;The self critic in me keeps on thinking about the lost game and the game which went to time, but some small part of me tries to point out that things actually went well. I felt fine in all games and it never felt hopeless in any game. I did take “better” or more serious decks and the other guys joked about my very serious decks, but it’s fine. I did accomplish my goal and I even won the tournament, yay!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/netrunner_summer_res.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;I managed to achieve my goal and I got to choose a playset of Aesops! I also got a couple of Swordsman and a new deckbox. It’s a little bit sad that I declined the Femme Fatale alt-art as it’s preeetty… But maybe next time.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/summer_winnings.jpg&quot; /&gt;
&lt;/figure&gt;</content></entry><entry><title>Netrunner ID draft Örebro</title><id>http://jonashietala.se/blog/2015/08/29/netrunner_id_draft_rebro/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/29/netrunner_id_draft_rebro" rel="alternate"/><published>2015-08-29T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I entered an ID draft tournament in &lt;a href=&quot;https://boardgamegeek.com/boardgame/124742/android-netrunner&quot; title=&quot;Android: Netrunner&quot;&gt;Netrunner&lt;/a&gt; hosted in Örebro and this is a brief overview of what happened. Disclaimer: My memory is a little bit fuzzy and the events may or may not correspond to what actually happened.&lt;/p&gt;
&lt;h1&gt;The draft&lt;/h1&gt;
&lt;p&gt;The idea was to randomly sort all entrants and in turn each chooses an ID which nobody else can choose. When everyone has chosen an ID the procedure continues in reverse order. This means you can choose either corp or runner early and leave the other until later.&lt;/p&gt;
&lt;p&gt;I got the 5th spot and Geist, Nasir, RP and NEH was chosen before me. If the goal was to do well I should probably have chosen a strong corp like Blue Sun, HB or possibly PE but I had just started playing Noise and I was loving every second of it so that was my choice. It was a little bit boring perhaps as it wasn’t a new ID I had to come up, but I had no idea of what I actually wanted to play with as corp so I simply delayed that decision. When it was my turn again most actually good corps had gone and I could choose between Titan, Harmony Medtech, Argus and Biotech (and some others…). Recently some popular Titan lists had popped up on netrunnerdb so I took that one.&lt;/p&gt;
&lt;p&gt;This is the drafting result:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/netrunner-ID-draft-2015-08-29.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Frida unfortunately did not attend the actual draft and she had to pick both runner and corp last.&lt;/p&gt;
&lt;p&gt;With Wayland and Jinteki being relatively popular I was thinking of adding I’ve had worse to Noise… But in the end I decided to be ballsy and skip all that. And no plascretes. But I thought with some careful play and Imp/Utopia shard I could manage. Instead I went with the no frills 3 Aesop/3 Cache low economy approach which I’ve found is perfectly fine. I slotted 2 Hacktivist meeting as the local playgroup in Linköping insisted on running Cerebral static and Manhunt and maybe others would do weird stuff with currents as well? &lt;a href=&quot;http://netrunnerdb.com/en/decklist/25730/the-original-hacker-rebro-id-draft-4th-&quot; title=&quot;Noise deck&quot;&gt;This is the Noise deck.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://netrunnerdb.com/en/decklist/25732/the-future-is-now-rebro-id-draft-4th-&quot; title=&quot;Titan deck&quot;&gt;The Titan build&lt;/a&gt; is basically the popular &lt;a href=&quot;http://netrunnerdb.com/en/decklist/24856/atlas-shrugged&quot; title=&quot;netrunnerdb: Atlas Shrugged&quot;&gt;Atlas Shrugged&lt;/a&gt; with Beanstalk replacing Subliminal messaging and an extra Crisium Grid for the relative increase of criminal. In testing the corp deck performed okay… But never amazing. Noise performed consistently whenever I didn’t just die against Jinteki due to… Jinteki stuff.&lt;/p&gt;
&lt;h1&gt;The matches&lt;/h1&gt;
&lt;p&gt;When we arrived at Örebro the basement already full of Magic gamers is already hot and things would only get worse. I didn’t get enough sleep and I’m already tired but still pumped to play some Netrunner!  The tournament features five rounds of swiss without a cut.&lt;/p&gt;
&lt;h2&gt;Match 1: Yoshi, Reina/Blue Sun&lt;/h2&gt;
&lt;p&gt;vs Reina&lt;/p&gt;
&lt;p&gt;Hedge fund, beanstalk, install ice over HQ. Runner installs things, runs on R&amp;amp;D and misses. I sea source-scorch second turn as he has 2 (or 3?) cards and I feel a bit bad about it. Unfortunately silly wins and losses like these happens sometimes.&lt;/p&gt;
&lt;p&gt;vs Blue Sun&lt;/p&gt;
&lt;p&gt;He gets a great start with ice and money. I’m having trouble setting up and I can’t find D4v1d before he can retrieve his oversighted Curtain Wall. I’m too scared/incapable of stealing his agendas as he’s rushing them out. When I finally get my Imp going on HQ he already has a scored atlas with two tokens and he scores out a hostile in a flash. I made a mistake of not installing a clone chip as I had a clot in my heap and I maybe should have been more aggressive but overall Yoshi outplayed me.&lt;/p&gt;
&lt;p&gt;2 points, 1-1&lt;/p&gt;
&lt;h2&gt;Match 2: Dan, TWIY/Whizzard&lt;/h2&gt;
&lt;p&gt;vs TWIY&lt;/p&gt;
&lt;p&gt;Dan is from Linköping, same as me, but I haven’t actually played him but I knew his was a variation of the &lt;a href=&quot;http://netrunnerdb.com/en/decklist/22037/when-the-flash-wears-yellow-v-2-undefeated-bratislava-regi&quot; title=&quot;netrunnerdb Flash&quot;&gt;Midseasons/Psychographics rush deck&lt;/a&gt;. I play very carefully and builds up while he takes money. He gets a bunch more money and I continue milling and building. I’m waiting for him to start scoring out and I go through a Tollbooth and imps away an NAPD contract, but he never gets the astro train going while I sit back milling with clot ready. The game basically end when he never scores out and I get a mill victory.&lt;/p&gt;
&lt;p&gt;vs Whizzard&lt;/p&gt;
&lt;p&gt;He trashes my sansans but I get some points scored. The game goes a bit long and we’re almost going to time. I think I could have won by rezzing an Archer against his faust when he doesn’t have enough cards to continue the game, but I stress out and for some reason I don’t rez it. Later he finds a 3-pointer for the win from HQ. I guess I took the risk as he could have just as easily hit a Snare and loose.&lt;/p&gt;
&lt;p&gt;4 points, 2-2&lt;/p&gt;
&lt;h2&gt;Match 3: Johannes, Harmony Medtech/Geist&lt;/h2&gt;
&lt;p&gt;vs Geist&lt;/p&gt;
&lt;p&gt;I’ve played against Johannes a lot so I know his deck and he knows mine. I get an excellent start with 3(!) Quandary protecting HQ, R&amp;amp;D and my remote. I manage to tax out his breaking and entering breakers as I score out with the help of sansan. Annoyingly Forger prevented me from scorching him more than once but in the end I manage to score out behind 2x barriers and a Quandary as he had basically exhausted his breakers and clone chips.&lt;/p&gt;
&lt;p&gt;vs Harmony Medtech&lt;/p&gt;
&lt;p&gt;I got set up with Noise fast and controlled the game from the start. He scored out a Nisei but I was never really worried. I made a stupid move of running archives when I had just trashed a Cyberdex and later I ran it again! But in the end my start was just too good and I won by pounding HQ with Lamprey, Imp and parasites.&lt;/p&gt;
&lt;p&gt;8 points, 4-2&lt;/p&gt;
&lt;h2&gt;Match 4: Magnus, Nisei Division/Valencia&lt;/h2&gt;
&lt;p&gt;vs Nisei Division&lt;/p&gt;
&lt;p&gt;I’ve never played Magnus but I know he’s a very good player so I’m really nervous to play him. He installs over R&amp;amp;D and remote and does a hedge fund. I install a lamprey and imp and run HQ… Just to hit a Snare. Sigh. I thought about it but I figured it wouldn’t be a big deal, but it was. I don’t shake the tag as I don’t have any resource installed and he scorches me. Huge misplay from me and now I’m trying not to tilt too hard.&lt;/p&gt;
&lt;p&gt;vs Valencia&lt;/p&gt;
&lt;p&gt;I have a fairly bad starting hand which I keep… For some unknown reason. He’s very aggressive and he gets a medium dig going but misses. I don’t care about it too much and continue trying to score/finding my pieces. He does another big medium dig through a Grim, paying 3 + 1 cards for it and another ice, and hits a Snare on his last click, with two cards left in hand. I have a jackson out so I click to draw two cards and find the scorch for the win.&lt;/p&gt;
&lt;p&gt;Funny how both games ends in basically the same way. I’m still a bit upset about the way I lost but it feels a little bit better that I could pull out a win against such a good player, even if it was a lucky one.&lt;/p&gt;
&lt;p&gt;10 points, 5-3&lt;/p&gt;
&lt;h2&gt;Match 5: Frida, Argus/Silhouette&lt;/h2&gt;
&lt;p&gt;vs Argus&lt;/p&gt;
&lt;p&gt;I know Frida loves meat damage so I play very carefully. I get a good start and I imp a bunch of things from R&amp;amp;D while milling a healthy amount. She scores out a couple of 1-pointers but I’m milling very fast and she’s not threatening me yet. When she goes up to 5 points I have as much money as she has so I make a run on archives (I also have an installed Utopia Shard) and take the win.&lt;/p&gt;
&lt;p&gt;vs Silhouette&lt;/p&gt;
&lt;p&gt;Again I get a good start and I get a Crisium grid on HQ to stop siphon. She doesn’t find her breakers and I get a hostile scored followed by the atlas train.&lt;/p&gt;
&lt;p&gt;14 points, 7-3&lt;/p&gt;
&lt;h1&gt;Final results&lt;/h1&gt;
&lt;p&gt;I won 7 matches, 4 with Titan and 3 with Noise. Surprisingly my corp faired better than my runner which can partly be explained by the two lucky flatlines I got. But overall it felt a lot better than during testing. Perhaps it’s because I’ve never played a rush deck before and the style takes a little getting used to? Then I got the silly scorched loss with Noise which really shouldn’t happen if you play as you should. But mistakes happen. I’m quite glad I managed to avoid tilting though.&lt;/p&gt;
&lt;p&gt;Generally with Noise I feel if the corp doesn’t push scoring windows hard you’re always in control of the game. Even then it’s difficult without a secondary win condition like scorch or midseasons. This is what Yoshi did with Blue Sun so very well where I really felt behind the whole game, but perhaps I was being too cautious.&lt;/p&gt;
&lt;p&gt;Overall I’m quite pleased with my result all things considered. This is the final results after the five rounds of swiss:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/netrunner-ID-draft-2015-08-29-results.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;There were quite a lot of prizes available and after the three victors took theirs this is what took home as my 4th place:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trimat_mat.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;I wanted to have a full playset of aesop’s, especially as I really love Noise, but the mat feels a little more special. I still want the alt-arts though, hopefully I can get them from somewhere else.&lt;/p&gt;
</content></entry><entry><title>Groar</title><id>http://jonashietala.se/blog/2015/08/23/xgroar/index.html</id><updated>2026-04-27T11:10:28+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/23/xgroar" rel="alternate"/><published>2015-08-23T13:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;h1&gt;Download&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;/games/groar.tar.gz&quot;&gt;Linux 64bit&lt;/a&gt;
&lt;a href=&quot;/games/groar.zip&quot;&gt;Windows&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So I actually &lt;a href=&quot;http://ludumdare.com/compo/ludum-dare-33/?action=preview&amp;amp;uid=1895&quot;&gt;finished&lt;/a&gt; Ludum Dare 33.  I can’t believe how hard it was to actually make something! It continues to amaze me what fantastic stuff everyone manage to make in just 48 hours. This is what I came up with for the theme &lt;em&gt;You are the Monster&lt;/em&gt;. Yes I couldn’t come up with a name until submission… So I just took the first admittedly bad one…&lt;/p&gt;
&lt;h1&gt;Groar&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/ld33/thumb1.png&quot; alt=&quot;&quot; /&gt; &lt;img src=&quot;/images/ld33/thumb2.png&quot; alt=&quot;&quot; /&gt; &lt;img src=&quot;/images/ld33/thumb3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Controls&lt;/h1&gt;
&lt;p&gt;W A S D moves and H J K L shoots. Escape quits the game.&lt;/p&gt;
&lt;h1&gt;Timelapse (dual screen)&lt;/h1&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=msRUwCWzPKA&quot;&gt;https://www.youtube.com/watch?v=msRUwCWzPKA&lt;/a&gt;
&lt;h1&gt;Timelapse (single screen)&lt;/h1&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=cgk-oiEMYZk&quot;&gt;https://www.youtube.com/watch?v=cgk-oiEMYZk&lt;/a&gt;
&lt;h1&gt;Source&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/ld33&quot;&gt;https://codeberg.org/treeman/ld33&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>Bullets and AI</title><id>http://jonashietala.se/blog/2015/08/23/bullets_and_ai/index.html</id><updated>2023-10-01T13:34:03+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/23/bullets_and_ai" rel="alternate"/><published>2015-08-23T12:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The game is still far from being an actual game but some progress has been made. I fixed most of the collision detection problems and I’m now trying to make some sort of AI working for the ship. It’s a bit hard and time consuming and I don’t know how to make things good.&lt;/p&gt;
&lt;p&gt;Maybe some time I need to focus on actually making graphics as well?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ld33/bullets_ai.png&quot; /&gt;
&lt;/figure&gt;</content></entry><entry><title>Life and Shields</title><id>http://jonashietala.se/blog/2015/08/23/life_and_shields/index.html</id><updated>2023-10-01T13:30:54+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/23/life_and_shields" rel="alternate"/><published>2015-08-23T11:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Time is running out! At least the more technical parts are &lt;em&gt;mostly&lt;/em&gt; done. The ships have an acceptable AI, they have rechargeable shields and they can now even be killed. Currently the game is far too easy, but it’s starting to look a little cooler at least.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ld33/lifenshields.png&quot; /&gt;
&lt;/figure&gt;</content></entry><entry><title>Settled on an unoriginal idea</title><id>http://jonashietala.se/blog/2015/08/22/settled_on_an_unoriginal_idea/index.html</id><updated>2023-10-01T13:33:53+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/22/settled_on_an_unoriginal_idea" rel="alternate"/><published>2015-08-22T10:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I think I’ve decided what to do. Some very slight progress has been made.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ld33/fugly_monster.png&quot; /&gt;
&lt;/figure&gt;</content></entry><entry><title>Fun or Frustration? Ludum Dare 33</title><id>http://jonashietala.se/blog/2015/08/21/fun_or_ludum_dare_33/index.html</id><updated>2026-04-27T11:09:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/21/fun_or_ludum_dare_33" rel="alternate"/><published>2015-08-21T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;One of &lt;a href=&quot;/blog/2014/12/31/2014_in_review/&quot; title=&quot;2014 in Review&quot;&gt;my goals this year&lt;/a&gt; was to participate in a &lt;a href=&quot;http://ludumdare.com/compo/&quot; title=&quot;Ludum Dare&quot;&gt;Ludum Dare&lt;/a&gt;. I have cleared up my schedule, negotiated with my better half and everything is set up for epicness.&lt;/p&gt;
&lt;p&gt;At first the idea was to make a game in &lt;a href=&quot;https://www.rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt;, even tough I basically haven’t used it in almost a year, but when I tried to set things up (yes today) it was extremely frustrating. Not so much that I couldn’t write rust code but more that documentaion for the game engine I used was lacking. In the end I decided to skip it as I couldn’t get sound to work.&lt;/p&gt;
&lt;p&gt;In a bit of a hurry I went back to what I’ve used before. I still couldn’t get the sound to work but I’m suspecting faulty sound libraries in my linux setup.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Language:&lt;/strong&gt; C++&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Framework:&lt;/strong&gt; &lt;a href=&quot;http://www.sfml-dev.org/&quot; title=&quot;SFML&quot;&gt;SFML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graphics:&lt;/strong&gt; &lt;a href=&quot;https://github.com/wjaguar/mtPaint&quot; title=&quot;mtPaint&quot;&gt;mtPaint&lt;/a&gt;, &lt;a href=&quot;https://inkscape.org/en/&quot; title=&quot;Inkscape&quot;&gt;Inkscape&lt;/a&gt;, &lt;a href=&quot;https://krita.org/&quot; title=&quot;Krita&quot;&gt;Krita&lt;/a&gt; (one of them at least?)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sound:&lt;/strong&gt; &lt;a href=&quot;http://www.bfxr.net/&quot; title=&quot;bfxr&quot;&gt;bfxr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As usual I will do it by myself. The goal is to make a simple reasonably complete game. The source code will be &lt;a href=&quot;https://codeberg.org/treeman/ld33&quot; title=&quot;Codeberg repository for Ludum Dare 33&quot;&gt;on github&lt;/a&gt; where I have a small code skeleton which I can use as a starting point.&lt;/p&gt;
</content></entry><entry><title>Mailto: links with FastMail in Firefox</title><id>http://jonashietala.se/blog/2015/08/13/mailto_links_with_fastmail_in_firefox/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/13/mailto_links_with_fastmail_in_firefox" rel="alternate"/><published>2015-08-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;You can change the application to handle &lt;code&gt;mailto:&lt;/code&gt; links in Firefox in Preferences -&amp;gt; Applications. The problem is that you can’t input custom urls and some email providers, like hotmail or fastmail, aren’t supported. I managed to fix it with the plugin &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/mailtowebmails/?src=search&quot; title=&quot;MailtoWebmails plugin for Firefox&quot;&gt;MailtoWebmails&lt;/a&gt;. It annoys me that a plugin is needed, but there it is.&lt;/p&gt;
</content></entry><entry><title>rustc: error while loading shared libraries: librustc_driver</title><id>http://jonashietala.se/blog/2015/08/12/rustc_error_while_loading_shared_libraries_librustcdriver/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/12/rustc_error_while_loading_shared_libraries_librustcdriver" rel="alternate"/><published>2015-08-12T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I had installed and used &lt;a href=&quot;https://github.com/rust-lang/rust&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; already but today I fired it up and received:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rustc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rustc:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; error while loading shared libraries: librustc_driver-7e44814b.so: cannot open shared object file: No such file or directory&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’ve seen this before… I thought modifying &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; in my shell was enough, but no. According to &lt;a href=&quot;https://github.com/rust-lang/rust/issues/24677&quot; title=&quot;The Bug&quot;&gt;the bug report&lt;/a&gt; the problem is with &lt;code&gt;ldconfig&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Edit &lt;code&gt;/etc/ld.so.conf&lt;/code&gt; and add &lt;code&gt;/usr/local/lib&lt;/code&gt; to it then run &lt;code&gt;ldconfig&lt;/code&gt; to update the cache. Now everything works again.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rustc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;version&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rustc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; 1.3.0-dev (4b4119d5c 2015-07-29&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta post-cmd shell&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not sure why it appeared again though.&lt;/p&gt;
</content></entry><entry><title>Moving to FastMail</title><id>http://jonashietala.se/blog/2015/08/10/moving_to_fastmail/index.html</id><updated>2023-10-01T13:27:50+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/10/moving_to_fastmail" rel="alternate"/><published>2015-08-10T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;About two years ago after &lt;a href=&quot;https://en.wikipedia.org/wiki/Lavabit&quot; title=&quot;Lavabit&amp;#39;s history&quot;&gt;Lavabit’s shutdown&lt;/a&gt; I searched for a replacement email provider. For some reason I settled on &lt;a href=&quot;http://www.eumx.net&quot; title=&quot;eumx.net&quot;&gt;eumx&lt;/a&gt; which I used since then. Yesterday I got an email saying the recurring billing could not be renewed as I had my old credit card registered and it got me thinking of moving on. I wasn’t particularly unhappy but I had some annoyances. Their webmails’ were a bit obnoxious to use but I could live with it. Something more alarming is that &lt;a href=&quot;http://www.eumx.net/contact.php&quot; title=&quot;eumx.net support&quot;&gt;they don’t use ssl consistently&lt;/a&gt;. I remember I pointed out this to them but at the moment it’s not fixed (or the error has returned).&lt;/p&gt;
&lt;p&gt;Whatever. &lt;a href=&quot;https://www.fastmail.com/&quot; title=&quot;FastMail&quot;&gt;FastMail&lt;/a&gt; often gets mentioned as a Gmail alternative and I decided to use them. Their webmail feels very, very good and it’s also possible to pay with &lt;a href=&quot;https://en.wikipedia.org/wiki/Bitcoin&quot; title=&quot;Bitcoin&quot;&gt;Bitcoin&lt;/a&gt;! This actually marks the first real purchase I’ve made with bitcoins and it was all very painless.&lt;/p&gt;
&lt;p&gt;It was easy to migrate my mail from eumx by using their migrate service from IMAP &lt;code&gt;ssl.eumx.net&lt;/code&gt;. Migrating from Gmail gave me more trouble as Gmail denied me access. After creating an app specific password I finally made it work. For more help see &lt;a href=&quot;https://www.fastmail.com/help/receive/migrate.html&quot;&gt;https://www.fastmail.com/help/receive/migrate.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Registering my own domain was very easy with the &lt;a href=&quot;https://www.fastmail.com/help/receive/domains.html&quot; title=&quot;Custom domain with FastMail&quot;&gt;instructions&lt;/a&gt;. I could not find instructions to setup DKIM specific for &lt;a href=&quot;https://loopia.se&quot; title=&quot;Loopia&quot;&gt;loopia&lt;/a&gt;, but it was easy enough to figure out.&lt;/p&gt;
&lt;p&gt;In a subdomain &lt;code&gt;mesmtp._domainkey&lt;/code&gt; set a TXT record with the value of the public key found in Advanced -&amp;gt; Virtual Domains -&amp;gt; DKIM signing keys.  You can check the settings with &lt;code&gt;dig&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ dig mesmtp._domainkey.jonashietala.se TXT
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;; &lt;&lt;&gt;&gt; DiG 9.9.3-P2 &lt;&lt;&gt;&gt; mesmtp._domainkey.jonashietala.se TXT
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;; global options: +cmd
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;; Got answer:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 29301
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;; OPT PSEUDOSECTION:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;; EDNS: version: 0, flags:; udp: 1280
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;; QUESTION SECTION:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;mesmtp._domainkey.jonashietala.se. IN	TXT
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;;; ANSWER SECTION:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;mesmtp._domainkey.jonashietala.se. 3600	IN TXT	&quot;v=DKIM1\; k=rsa\; 
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpqEJlGriDgRE6qjys7e424xv5K9LAJrvTQ8/K8Lj4h
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where you should see the public key. After the settings have propagated the Set field under DKIM signing keys should change from &lt;code&gt;[]&lt;/code&gt; to &lt;code&gt;[*]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I’m also trying out two factor authentication with &lt;a href=&quot;https://en.wikipedia.org/wiki/Google_Authenticator&quot; title=&quot;Google Authenticator&quot;&gt;Google Authenticator&lt;/a&gt;. Although FastMail implements it in a strange way, using a base password and then appending the OTP from the authenticator. It’s a bit annoying but it works I guess.&lt;/p&gt;
&lt;p&gt;Overall &lt;a href=&quot;https://www.fastmail.com/&quot; title=&quot;FastMail&quot;&gt;FastMail&lt;/a&gt; seems very good, the little I’ve used it, and it might be worth taking a look at.&lt;/p&gt;
</content></entry><entry><title>Drawing a self portrait</title><id>http://jonashietala.se/blog/2015/08/08/drawing_a_self_portrait/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/08/drawing_a_self_portrait" rel="alternate"/><published>2015-08-08T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Drawing is hard. I’d like to improve though. Here’s a self portrait I tried to draw in &lt;a href=&quot;https://krita.org&quot; title=&quot;Krita&quot;&gt;Krita&lt;/a&gt;. I’m really slow so I stopped a bit before it really was finished.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/drawing/me/me_crop.png&quot; /&gt;
&lt;/figure&gt;&lt;figure&gt;
&lt;img src=&quot;/images/drawing/me/me_drawing.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Obviously I’d like it to be a bit better, but I’m still a little happy about the glasses and the eyebrows. The mouth and nose is ugly though.&lt;/p&gt;
</content></entry><entry><title>Gruvbox Syntax Highlighting for Pandoc</title><id>http://jonashietala.se/blog/2015/08/04/gruvbox_syntax_highlighting_for_pandoc/index.html</id><updated>2026-04-27T11:10:07+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/04/gruvbox_syntax_highlighting_for_pandoc" rel="alternate"/><published>2015-08-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; I have &lt;a href=&quot;/blog/2019/01/25/site_restyle_and_update#changes-to-code-display&quot; title=&quot;Site restyle and update: Changes to code display&quot;&gt;updated the highlighting&lt;/a&gt; again so the inline code used as examples have changed. I guess I should’ve used images to record the look.&lt;/p&gt;
&lt;p&gt;Recently when I &lt;a href=&quot;/blog/2015/08/02/slackware_update&quot; title=&quot;Reinstall Slackware&quot;&gt;reinstalled Slackware&lt;/a&gt; I decided to restyle my workspace as well. I settled on &lt;a href=&quot;https://github.com/morhetz/gruvbox&quot; title=&quot;Gruvbox for vim&quot;&gt;gruvbox&lt;/a&gt; with neovim and using &lt;a href=&quot;https://github.com/morhetz/gruvbox-generalized&quot; title=&quot;Gruvbox generalized&quot;&gt;the generalized&lt;/a&gt; package I also styled my terminal.&lt;/p&gt;
&lt;p&gt;Then on a whim I wanted to restyle this site. When I built it I kinda left it without any styling at all, I guess the thinking was that it works and I can just tweak it later. Well it’s been more than 2 years now and I never got around to it. I guess what bothered me the most was the fact that I had a really crappy styling syntax highlighting and styling of code. So I decided to change it.&lt;/p&gt;
&lt;p&gt;I couldn’t find any reference to highlighting pandoc styled like gruvbox, so I tried to emulate on myself. I use the darker one in neovim and in the terminal, but for the web page I used the lighter one:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;css&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight css&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;, &lt;span class=&quot;entity name tag css&quot;&gt;pre&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;background-color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;f2e5bc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Hard contrast &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;kw&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;9d0006&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Keyword red &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;dt&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;b57614&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Datatype yellow &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;dv&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;8f3f71&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; DecVal purple &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;bn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;8f3f71&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; BaseN purple &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;fl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;8f3f71&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Float purple &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;ch&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;4070a0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Char purple &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;st&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;79740e&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; String green &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;co&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;928374&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-style&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;italic&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Comment medium &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;ot&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;427b56&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; OtherToken aqua &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;fu&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;79740e&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Function green &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;re&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;af3a03&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Region marker orange &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;er&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;9d0006&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-weight&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;bold&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Error red &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;sourceCode&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;al&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;color&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant other color rgb-value css&quot;&gt;&lt;span class=&quot;punctuation definition constant css&quot;&gt;#&lt;/span&gt;9d0006&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-weight&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;bold&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;comment block css&quot;&gt;&lt;span class=&quot;punctuation definition comment css&quot;&gt;/*&lt;/span&gt; Alert red &lt;span class=&quot;punctuation definition comment css&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works with the &lt;a href=&quot;http://hackage.haskell.org/package/highlighting-kate&quot; title=&quot;The highlighting-kate package&quot;&gt;highlighting-kate package&lt;/a&gt; which is what &lt;a href=&quot;http://pandoc.org/index.html&quot; title=&quot;Pandoc&quot;&gt;pandoc&lt;/a&gt;, and therefore &lt;a href=&quot;http://jaspervdj.be/hakyll/&quot; title=&quot;Hakyll&quot;&gt;Hakyll&lt;/a&gt;, is using.&lt;/p&gt;
&lt;p&gt;Additionally to get nicer spacing and font these styles are used:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;css&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight css&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;string unquoted css&quot;&gt;Consolas&lt;/span&gt;&lt;span class=&quot;punctuation separator css&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;string quoted double css&quot;&gt;&lt;span class=&quot;punctuation definition string begin css&quot;&gt;&amp;quot;&lt;/span&gt;Courier New&lt;span class=&quot;punctuation definition string end css&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator css&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;support constant font-name css&quot;&gt;monospace&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;font-size&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;0.9&lt;span class=&quot;keyword other unit css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;0.2&lt;span class=&quot;keyword other unit css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;line-height&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;1.3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;pre&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;word-wrap&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;normal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;overflow&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;auto&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;0.6&lt;span class=&quot;keyword other unit css&quot;&gt;em&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;constant numeric css&quot;&gt;1.0&lt;span class=&quot;keyword other unit css&quot;&gt;em&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;line-height&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;1.3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity name tag css&quot;&gt;pre&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;code&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Currently I’m happy with the result and you can view the source of this site at &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;https://codeberg.org/treeman/jonashietala&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><title>fish_update_completions in Slackware 14.1</title><id>http://jonashietala.se/blog/2015/08/03/fish_update_completions_slackware/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/03/fish_update_completions_slackware" rel="alternate"/><published>2015-08-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been trying out &lt;a href=&quot;http://fishshell.com&quot; title=&quot;fish shell&quot;&gt;fish shell&lt;/a&gt; lately. A cool feature with fish is that it can automatically generate completions by parsing the installed man pages by running &lt;code&gt;fish_update_completions&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately this is what I got:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Traceback (most recent call last):
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  File &quot;/usr/local/share/fish/tools/create_manpage_completions.py&quot;, line 963, in &lt;module&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    file_paths.extend(get_paths_from_manpath())
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  File &quot;/usr/local/share/fish/tools/create_manpage_completions.py&quot;, line 894, in get_paths_from_manpath
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    proc = subprocess.Popen([&apos;manpath&apos;], stdout=subprocess.PIPE)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  File &quot;/usr/lib64/python2.7/subprocess.py&quot;, line 711, in __init__
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    errread, errwrite)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  File &quot;/usr/lib64/python2.7/subprocess.py&quot;, line 1308, in _execute_child
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    raise child_exception
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;OSError: [Errno 2] No such file or directory
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The solution for me was to install &lt;code&gt;man-db&lt;/code&gt; from Slackbuilds and add &lt;code&gt;/opt/man-db/bin&lt;/code&gt; and &lt;code&gt;/opt/man-db/sbin&lt;/code&gt; to PATH to get fish to find the command &lt;code&gt;manpath&lt;/code&gt;. The dependency for &lt;code&gt;man-db&lt;/code&gt; is undocumented but it’s a known issue.&lt;/p&gt;
&lt;p&gt;During the installation I got several strange errors &lt;code&gt;error: cannot run C compiled programs&lt;/code&gt; which I have no idea why they came up. Eventually by retrial I got it to work.&lt;/p&gt;
&lt;p&gt;Curiouly enough fish couldn’t parse several of the slackware specific man pages. I manually made completions for &lt;code&gt;exlodepkg&lt;/code&gt;, &lt;code&gt;installpkg&lt;/code&gt;, &lt;code&gt;makepkg&lt;/code&gt;, &lt;code&gt;removepkg&lt;/code&gt;, &lt;code&gt;slackpkg&lt;/code&gt; and &lt;code&gt;upgradepkg&lt;/code&gt; which can be found at &lt;a href=&quot;https://github.com/treeman/dotfiles/tree/master/.config/fish/completions&quot;&gt;https://github.com/treeman/dotfiles/tree/master/.config/fish/completions&lt;/a&gt;. Of these removepkg was the real motivator as natively it didn’t autocomplete installed packages. I added the rest more for the sake of completeness. These are not super great and I’m not sure if anyone else will find it useful. I might consider trying to add them to fish later.&lt;/p&gt;
</content></entry><entry><title>Installing Krita on Slackware 14.1</title><id>http://jonashietala.se/blog/2015/08/03/installing_krita_on_slackware/index.html</id><updated>2023-10-01T13:27:08+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/03/installing_krita_on_slackware" rel="alternate"/><published>2015-08-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is a guide on how to build &lt;a href=&quot;https://krita.org/&quot; title=&quot;Krita Digital Painting&quot;&gt;Krita&lt;/a&gt; on Slackware 14.1. This is based on &lt;a href=&quot;http://www.davidrevoy.com/article193/guide-building-krita-on-linux-for-cats&quot; title=&quot;Install Krita&quot;&gt;this guide for linux&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;removepkg calligra&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install some dependencies from &lt;a href=&quot;http://slackbuilds.org&quot; title=&quot;Slackbuilds&quot;&gt;Slackbuilds&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;gsl
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;libgexiv2
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;libpqxx
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;pstoedit
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get Krita.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.davidrevoy.com/article193/guide-building-krita-on-linux-for-cats&quot; title=&quot;Install Krita&quot;&gt;original guide&lt;/a&gt; recommends building in &lt;code&gt;~/kde4&lt;/code&gt; but I moved i to &lt;code&gt;/opt/kde4&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;mkdir&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;p&lt;/span&gt; /opt/kde4/build /opt/kde4/src /opt/kde4/inst&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; /opt/kde4/src&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;git&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; clone git://anongit.kde.org/calligra.git&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure and build.&lt;/p&gt;
&lt;p&gt;There’s a problem with tifflib. (My version is &lt;code&gt;Krita: 2.9.6 (gitb804a35)&lt;/code&gt;, you may or may not run into this problem).&lt;/p&gt;
&lt;p&gt;Change &lt;code&gt;/opt/kde4/src/calligra/krita/plugins/formats/tiff/kis_tiff_converter.cc&lt;/code&gt; from&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;C&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight C&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor c&quot;&gt;&lt;span class=&quot;keyword control import c&quot;&gt;#if&lt;/span&gt; TIFFLIB_VERSION &amp;lt; 20111221
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;tmsize_t&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor c&quot;&gt;&lt;span class=&quot;keyword control import c&quot;&gt;#endif&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;C&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight C&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;tmsize_t&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can build&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; /opt/kde4/build&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cmake&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;DCMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class=&quot;keyword operator assignment option shell&quot;&gt;=&lt;/span&gt;/opt/kde4/inst /opt/kde4/src/calligra &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;    -&lt;/span&gt;DCMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class=&quot;keyword operator assignment option shell&quot;&gt;=&lt;/span&gt;RelWithDebInfo&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;DPRODUCTSET&lt;/span&gt;&lt;span class=&quot;keyword operator assignment option shell&quot;&gt;=&lt;/span&gt;KRITA&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;j5&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;j5&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where &lt;code&gt;X&lt;/code&gt; in &lt;code&gt;jX&lt;/code&gt; is &lt;code&gt;1 + # processors&lt;/code&gt;. The build process is quite slow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;code&gt;/opt/kde4/inst/bin&lt;/code&gt; to PATH and &lt;code&gt;/opt/kde4/inst&lt;/code&gt; to KDEDIRS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Register krita to the system &lt;code&gt;kbuildsyscoca4&lt;/code&gt;, but worked for me without it (I don’t use kde).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And launch with &lt;code&gt;krita&lt;/code&gt;.&lt;/p&gt;
</content></entry><entry><title>Preventing Firefox from creating Desktop directories</title><id>http://jonashietala.se/blog/2015/08/02/preventing_firefox_from_creating_desktop_directories/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/02/preventing_firefox_from_creating_desktop_directories" rel="alternate"/><published>2015-08-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;With a fresh firefox installation I found that it kept creating a &lt;code&gt;~/Desktop&lt;/code&gt; directory. But &lt;a href=&quot;http://www.kariliq.nl/misc/firefox-dirs.html&quot;&gt;I found how to turn it off&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Edit &lt;code&gt;~/.config/user-dirs.dirs&lt;/code&gt; to&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;XDG_DESKTOP_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;XDG_DOCUMENTS_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;XDG_DOWNLOAD_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;XDG_MUSIC_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;XDG_PICTURES_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;XDG_PUBLICSHARE_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;XDG_TEMPLATES_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;XDG_VIDEOS_DIR=&quot;$HOME/&quot;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I had &lt;code&gt;XDG_DESKTOP_DIR=&quot;$HOME/Desktop&quot;&lt;/code&gt; which made a Desktop folder all the time.&lt;/p&gt;
</content></entry><entry><title>Slackware update</title><id>http://jonashietala.se/blog/2015/08/02/slackware_update/index.html</id><updated>2023-09-18T14:59:54+00:00</updated><link href="https://www.jonashietala.se/blog/2015/08/02/slackware_update" rel="alternate"/><published>2015-08-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The last time I (re)installed Slackware &lt;a href=&quot;/blog/2014/07/05/reinstalling_slackware/&quot; title=&quot;Reinstalling Slackware&quot;&gt;I documented what I did&lt;/a&gt;. Somehow I managed to really bork my installation and I decided to go through with a larger reinstallation once more. This is a log of some things I did differently.&lt;/p&gt;
&lt;h1&gt;Kernel&lt;/h1&gt;
&lt;p&gt;Before installing the kernel it’s nice to check the GPG signature of the downloaded packages. With the &lt;a href=&quot;https://www.kernel.org/signature.html&quot; title=&quot;kernel.org signature&quot;&gt;kernel GPG signature&lt;/a&gt; we can simply do:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;wget&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; linux-XX.tar.xz&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;wget&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; linux-XX.tar.sign&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;unxz&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; linux.tar.xz&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;gpg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;verify&lt;/span&gt; &lt;span class=&quot;keyword operator regexp quantifier shell&quot;&gt;*&lt;/span&gt;.sign&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When making oldconfig &lt;code&gt;yes &quot;&quot; | oldconfig&lt;/code&gt; saves time.&lt;/p&gt;
&lt;h1&gt;Slackpkg&lt;/h1&gt;
&lt;p&gt;I didn’t use this tool previously, but it can be used to update the official Slackware packages. Just remember to update the gpg signature as well.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;slackpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; update&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;slackpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; update gpg&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I didn’t take the plunge to slackware-current just yet, I might do it at a later time when I feel I have a lot of unused time (will I ever?), but it’s easy to update selected packages.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;slackpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; upgrade git&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Will only update git for example.&lt;/p&gt;
&lt;h1&gt;Perl&lt;/h1&gt;
&lt;p&gt;I did some strange things here, the one which worked was simply as root:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install CPAN&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install DateTime&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Slackbuilds with &lt;a href=&quot;http://www.sbopkg.org/&quot; title=&quot;sbopkg&quot;&gt;sbopkg&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://slackbuilds.org/&quot; title=&quot;Slackbuilds&quot;&gt;Slackbuilds&lt;/a&gt; works well but can be cumbersome. &lt;a href=&quot;http://www.sbopkg.org/&quot; title=&quot;sbopkg&quot;&gt;sbopkg&lt;/a&gt; is a great little tool which makes downloading and installing much easier.&lt;/p&gt;
&lt;h1&gt;Hakyll and xmonad&lt;/h1&gt;
&lt;p&gt;This gave me a &lt;em&gt;lot&lt;/em&gt; of problems. At first I installed xmonad and xmonad-contrib from slackbuilds and I tried to install &lt;a href=&quot;https://github.com/jaspervdj/hakyll&quot; title=&quot;Hakyll&quot;&gt;Hakyll&lt;/a&gt; from cabal, but conflicts ensued and they couldn’t really work together.&lt;/p&gt;
&lt;p&gt;I tried to move cabal out from my home director, but didn’t find a very satisfactory solution and in the end I just gave up.&lt;/p&gt;
&lt;p&gt;The first thing to do is to install ghc from slackbuilds. Then install the Cabal lib and cabal-install from &lt;a href=&quot;https://github.com/haskell/cabal/releases&quot;&gt;https://github.com/haskell/cabal/releases&lt;/a&gt; (they are in the same lib).&lt;/p&gt;
&lt;p&gt;Then install a newer version of ghc from their prebuilt binaries at &lt;a href=&quot;https://www.haskell.org/ghc&quot;&gt;https://www.haskell.org/ghc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There I got the error that &lt;code&gt;libtinfo.so.5&lt;/code&gt; couldn’t be found. This was solved by symlinking to libncurses with &lt;code&gt;ln -s /lib64/libncurses.so.5 /lib64/libtinfo.so.5&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then we can install things with cabal as a regular user:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install cabal-install&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install hscolour&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install missingH&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install hakyll&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install xmonad&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install xmonad-contrib&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you get the error:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;pandoc-1.15.0.6 failed during the configure step. The exception was:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;user error (&apos;/usr/bin/ghc&apos; exited with an error:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;/usr/lib64/ghc-7.8.4/unix-2.7.0.1/libHSunix-2.7.0.1.a(execvpe.o): In function
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;`pPrPr_disableITimers&apos;:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;execvpe.c:(.text+0x300): multiple definition of `pPrPr_disableITimers&apos;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;/root/.cabal/lib/x86_64-linux-ghc-7.8.4/unix-2.7.1.0/libHSunix-2.7.1.0.a(ghcrts.o):(.text+0x0):
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;first defined here
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Try rerunning &lt;code&gt;cabal install cabal-install&lt;/code&gt; and then try to install hakyll again. This shouldn’t happen with an updated ghc though.&lt;/p&gt;
&lt;h1&gt;From source&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;fish shell&lt;/li&gt;
&lt;li&gt;neovim (xclip from slackbuilds)&lt;/li&gt;
&lt;li&gt;rust (nightly build)&lt;/li&gt;
&lt;li&gt;dzen2 (edit &lt;code&gt;config.mk&lt;/code&gt; and use Xinerama, XPM and XFT)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you get&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;rustc: error while loading shared libraries: librustc_driver-7e44814b.so:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;cannot open shared object file: No such file or directory
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;it’s because rust installed it in &lt;code&gt;/usr/local/lib&lt;/code&gt; which is not in the default search path. Can add &lt;code&gt;/usr/local/lib&lt;/code&gt; to &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; or issue &lt;code&gt;ldconfig /usr/local/lib&lt;/code&gt; for instant gratification.&lt;/p&gt;
&lt;h1&gt;Perl6&lt;/h1&gt;
&lt;p&gt;This can be done with everything as regular user.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;git&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; clone https://github.com/tadzik/rakudobrew &lt;span class=&quot;meta group expansion tilde&quot;&gt;&lt;span class=&quot;variable language tilde shell&quot;&gt;~&lt;/span&gt;&lt;/span&gt;/.rakudobrew&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add &lt;code&gt;~/.rakudobrew/bin&lt;/code&gt; to path.  Then we can install package manager panda and VM moar:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rakudobrew&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; build moar&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rakudobrew&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; build-panda&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then with panda we can install modules:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;panda&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install Task::Star&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Postgres&lt;/h1&gt;
&lt;p&gt;Install from slackbuilds. Check readme!  After installation, to allow for no password for postgres (useful for pure local) alter &lt;code&gt;/var/lib/pgsql/9.4/data/pg_hba.conf&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;and add the line&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;local   all     postgres    trust
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;before all other configurations.&lt;/p&gt;
&lt;h1&gt;Missing&lt;/h1&gt;
&lt;p&gt;This time I’m having trouble with getting sound working in Skype. To be continued… Maybe.&lt;/p&gt;
</content></entry><entry><title>5 Years at Linköping&apos;s University</title><id>http://jonashietala.se/blog/2015/07/22/5_years_at_the_university/index.html</id><updated>2026-04-27T11:10:39+00:00</updated><link href="https://www.jonashietala.se/blog/2015/07/22/5_years_at_the_university" rel="alternate"/><published>2015-07-22T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I recently finished my master’s degree (civilingenjör or civil engineering) at Linköping’s University. At first it felt like 5 years would be an eternity, but in hindsight it was over in a flash. my gut feeling is that I haven’t learnt or done anything of note, except you know actually finishing my degree, but if I sit down and think about it I have done some things. Actually quite a lot of things.&lt;/p&gt;
&lt;h1&gt;First year&lt;/h1&gt;
&lt;p&gt;I moved to Linköping with my girlfriend and it was quite an adjustment as we both moved from our parents and to a city where we practically knew nothing and no one. But we managed fine and while we never went out to parties or went to other student events we found some friends. I also started &lt;a href=&quot;http://linkoping-taekwondo.se/&quot; title=&quot;ITF Taekwon-do in Linköping&quot;&gt;ITF Taekwon-do&lt;/a&gt; after a few months.&lt;/p&gt;
&lt;p&gt;There weren’t too much to do in school. The focus was on foundation math courses, mostly things I had already done but needed refreshing, and on introductory programming courses which weren’t challenging at all for me.&lt;/p&gt;
&lt;h1&gt;Second year&lt;/h1&gt;
&lt;p&gt;During the second year I felt the courses were harder and more interesting than the first year’s courses. The courses in Combinatorial Optimization, Data Structures and Algorithms and Linear Algebra were fun and new for me. I also took an extra continuation course in Linear Algebra which was interesting.&lt;/p&gt;
&lt;p&gt;When I started the university I thought I would like electronics and hardware construction, but the courses from the first year were really not interesting at all. Even when making the transition from analog to digital I didn’t care for it at all. But it all changed when we started actually &lt;em&gt;building&lt;/em&gt; things with digital circuits.&lt;/p&gt;
&lt;p&gt;At first we had an introductory course where we built digital clocks and counters. You were supposed to have prepared a design sketch for the labs, but me and my partner for some reason never did it, and so we were always running late in the labs. I remember one very fun, or horrible, occasion where we had struggled a lot with one lab and we had spent almost the full 4 hours until we finally completed it with maybe 10 - 15 minutes left. Filled with relief we started taring apart what we so painstakingly had built. When done we realized we had one part left where we were supposed to use the circuit we just destroyed… Luckily we could use the circuits another group had made, but it was a painful lesson in always reading the descriptions and prepare for the labs in advance.&lt;/p&gt;
&lt;p&gt;The digital circuit labs were followed by a digital project of our own choice. We &lt;a href=&quot;https://codeberg.org/treeman/MARC&quot; title=&quot;Memory Array Redcode Computer&quot;&gt;designed a processor&lt;/a&gt; which could run the &lt;a href=&quot;http://corewar.co.uk/icws88.txt&quot; title=&quot;Core Wars 88 standard&quot;&gt;Core Wars 88 standard&lt;/a&gt; and we simulated it on an FPGA.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/marc_schema.png&quot; /&gt;
&lt;figcaption&gt;The main block schema for the processor&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And here is a small video of the simulation in action:&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=E2sehbjNtDg&quot;&gt;https://www.youtube.com/watch?v=E2sehbjNtDg&lt;/a&gt;
&lt;p&gt;The project was interesting as it was an outlet for our creativity and it touched on several different areas. Processor design, hardware debugging (!) and I wrote a &lt;a href=&quot;https://codeberg.org/treeman/MARC/src/branch/master/scripts/assembler&quot;&gt;redcode assembler&lt;/a&gt; for our CPU and a &lt;a href=&quot;https://codeberg.org/treeman/MARC/src/branch/master/scripts/control_codes&quot;&gt;microcode compiler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The behaviour of the processor is controlled by microcode which basically is a set of control outputs of 0s and 1s. For example our processor has 18 outputs consisting of a total of 39 bits (&lt;code&gt;uPC_addr&lt;/code&gt; is internal).&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;game FIFO IR ADR1 ADR2 OP M1 M2 mem1 mem2 mem3 mem_addr ALU1 ALU2 ALU buss PC  uPC  uPC_addr
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; 00   00  0   00  00   0  00 00  00   00   00    000     00   0   000 000  00 00000 00000000
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make things easier, instead of manually editing each 0/1 line we introduced a DSL which then the compiler turns into microcode lines.&lt;/p&gt;
&lt;p&gt;For example &lt;a href=&quot;https://codeberg.org/treeman/MARC/src/branch/master/scripts/microcode&quot;&gt;the microcode&lt;/a&gt; is described in our DSL:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;; Startup, check if we&apos;re in game
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        jmpS $GAME                              ; Execute game code only if we&apos;re running
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        jmpO +0                                 ; Infinite loop if we&apos;ve recieved game over, reset to break it
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;; Clear memory contents
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ALU = 0                                 ; Load 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ALU1 -&gt; buss, buss -&gt; OP, buss -&gt; M1, buss -&gt; M2, buss -&gt; PC
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;:CLRMEM PC -&gt; mem_addr                          ; Look at PC
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        OP -&gt; mem, M1 -&gt; mem, M2 -&gt; mem         ; Clear it
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ALU++                                   ; Incr
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ALU1 -&gt; PC, jmpZ $LOADP                 ; If 0 we&apos;re done looping
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        jmp $CLRMEM                             ; Else continue
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And is then compiled into &lt;a href=&quot;https://codeberg.org/treeman/MARC/src/branch/master/src/MARC/microcontroller.vhd&quot;&gt;VHDL code&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;vhdl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight vhdl&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword language vhdl&quot;&gt;signal&lt;/span&gt; mem &lt;span class=&quot;punctuation vhdl&quot;&gt;:&lt;/span&gt; Data &lt;span class=&quot;keyword operator vhdl&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;punctuation vhdl&quot;&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; Startup, check if we&amp;#39;re in game
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000000000000000000000000011000110011&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; jmpS GAME(33)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000000000000000000000000101000000001&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; jmpO +0(01)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; Clear memory contents
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000000000000000110000000000000000000&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; ALU = 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000010101000000000000000100010000000000000&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; ALU1 -&amp;gt; buss, buss -&amp;gt; OP, buss -&amp;gt; M1, buss -&amp;gt; M2, buss -&amp;gt; PC
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000000000110000000000000000000000000&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; PC -&amp;gt; mem_addr
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000101010000000000000000000000000000&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; OP -&amp;gt; mem, M1 -&amp;gt; mem, M2 -&amp;gt; mem
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000000000000000100000000000000000000&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; ALU++
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000000000000000000100010001100001001&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; ALU1 -&amp;gt; buss, buss -&amp;gt; PC, jmpZ LOADP(09)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;constant numeric quoted double string binary vhdl&quot;&gt;&amp;quot;00000000000000000000000000000000000001000000100&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation vhdl&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-dash vhdl&quot;&gt;&lt;span class=&quot;punctuation definition comment vhdl&quot;&gt;--&lt;/span&gt; jmp CLRMEM(04)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation accessor vhdl&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation accessor vhdl&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;punctuation accessor vhdl&quot;&gt;.&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The redcode assemblers job is to transform a warrior (a piece of redcode) into a binary object file which we can then send to the FPGA for execution.&lt;/p&gt;
&lt;p&gt;For example this warrior:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;step    EQU 417
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;init    EQU 1337
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;size    EQU 9
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        JMP start           ; boot jump as we can&apos;t specify PC in the middle T.T
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;src     DAT 0               ; src pointer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;start   MOV #size, src      ; setup src pointer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;copy    MOV @src, &lt;dst      ; copy self
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        DJN copy, src
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        SPL @dst            ; throw a pc there
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        ADD #step, dst      ; space out a bit
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        JMP start           ; make a new copy, yay!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;dst     DAT #0, #init       ; dst pointer
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;end
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compiles to:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ ./assembler jonas-replicator.red -r
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;0000000000001001
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000000100000000000000000000100000000000000000
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000000000000000000000000000000000000000000000
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000000001010000000000000010010001111111111111
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000000001101100011111111111100000000000000101
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000001001000000011111111111110001111111111101
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000001010100000000000000000110000000000000000
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000000010010000000001101000010000000000000010
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000000100000000011111111110110000000000000000
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;000000000000010100000000000000000000010100111001
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the &lt;code&gt;--verbose&lt;/code&gt; tag the format can be examined:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ ./assembler jonas-replicator.red --verbose
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;0000000000001001  00 09  ; Number of rows (9) jonas-replicator.red
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   pad    OP  A  B  pad     A op      pad      B op
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 0100 00 00 000 0000000000010 000 0000000000000   00 40 00 02 00 00  ; JMP  start           (2)  0(0)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 0000 00 00 000 0000000000000 000 0000000000000   00 00 00 00 00 00  ; DAT  0               (0)  0(0)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 0001 01 00 000 0000000001001 000 1111111111111   00 14 00 09 1f ff  ; MOV # size(9)  src       (-1)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 0001 10 11 000 1111111111110 000 0000000000101   00 1b 1f fe 00 05  ; MOV @ src(-2) &lt; dst      (5)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 1001 00 00 000 1111111111111 000 1111111111101   00 90 1f ff 1f fd  ; DJN  copy(-1)  src(-3)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 1010 10 00 000 0000000000011 000 0000000000000   00 a8 00 03 00 00  ; SPL @ dst            (3)  0(0)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 0010 01 00 000 0000110100001 000 0000000000010   00 24 01 a1 00 02  ; ADD # step(417)  dst      (2)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 0100 00 00 000 1111111111011 000 0000000000000   00 40 1f fb 00 00  ; JMP  start           (-5)  0(0)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;00000000 0000 01 01 000 0000000000000 000 0010100111001   00 05 00 00 05 39  ; DAT # 0(0) # init       (1337)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you’re interested in the project you can &lt;a href=&quot;https://codeberg.org/treeman/MARC&quot; title=&quot;Memory Array Redcode Computer&quot;&gt;read more on github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In addition, or as a prerequisite, to this awesome project we also got an introduction to 68k assembly and to computer architecture which was very good.&lt;/p&gt;
&lt;p&gt;This year me and a friend also made game in the Java programming course called &lt;a href=&quot;/blog/2011/10/19/grand_thief_arto/&quot; title=&quot;Grand Thief Arto&quot;&gt;Grand Thief Arto&lt;/a&gt;. Not the greatest of games but it was still fun to make it. I also became a mentor in discrete math for the first year students which was a fun and easy way to earn a bit of extra money.&lt;/p&gt;
&lt;h1&gt;Third year&lt;/h1&gt;
&lt;p&gt;This year we continued with some more advanced courses. We had some project oriented courses with some theory about how projects should be run and then a practical part where we made some software for an actual company. The overall idea the course idea is great, to get some real world experience and to get some interaction with an actual company, but the execution was very much not so.&lt;/p&gt;
&lt;p&gt;For example in the middle of the project one of our project members were supposed to be exchanged with another member from another project. The motivation was that “in the real world this could happen, so you need to always be prepared” but that’s just stupid in my opinion. Firstly you don’t get fired and just booted from the team very often, but you get an advanced notice and you have some time to prepare the team, yourself and your eventual replacement for the move. Secondly it adds a very real sense of dread and nervousness for everyone involved. I happened to really like all members in the project and I was very worried to be switched out. Turns out I was the one who had to change project. I was very upset and I didn’t click nearly as well with the new team and I thought the experience really sucked and I became demotivated.&lt;/p&gt;
&lt;p&gt;Another thing which was quite bad was the extreme focus on documentation. The whole first 2-3 months were supposed to be a planning stage and the actual implementation was supposed to be done the last 2-3 months. But large parts of the implementation stage were also spent on documentation, or rather writing documents because the course demanded it and we never had any use for the majority. The funny thing is that most of the project theory was spent on motivating why the waterfall development model wasn’t suited to software development, but what did the project degenerate into? Even despite our best efforts, we tried to implement an iterative development as our customers didn’t really know what they wanted, but we were foiled by course planners.&lt;/p&gt;
&lt;p&gt;A much better project was the &lt;a href=&quot;/blog/2013/01/20/i_robot/&quot; title=&quot;Our robot project&quot;&gt;Robot project&lt;/a&gt; where we created an autonomous robot! There we poked around with hardware and lower level programming in C.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trap14/Robot_0018.JPG&quot; /&gt;
&lt;figcaption&gt;Debugging this was quite an experience&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I continued to be a mentor in discrete math and I joined &lt;a href=&quot;http://obelix.cyd.liu.se/&quot;&gt;Team Obelix&lt;/a&gt; which organized student visits to different companies. I won the “best CV” award given by Ericsson, I won some things in the local programming competition &lt;a href=&quot;https://www.ida.liu.se/projects/impa/new/results&quot; title=&quot;IDA Mästerskapet i Programmering och Algoritmer&quot;&gt;IMPA&lt;/a&gt; and I had a great course in operative systems where we used &lt;a href=&quot;http://web.stanford.edu/class/cs140/projects/pintos/pintos.html&quot;&gt;Pintos&lt;/a&gt;. I took an extra course in Graph Theory which was quite different from other math courses but very interesting. Additionally I took a &lt;a href=&quot;https://www.coursera.org/course/proglang&quot;&gt;Programming Languages&lt;/a&gt; course at Coursera, also quite nice.&lt;/p&gt;
&lt;p&gt;This summer I also had my first real programming job which was a summer internship at &lt;a href=&quot;http://www.configura.com/&quot; title=&quot;Configura&quot;&gt;Configura&lt;/a&gt; and I had a really good time and we replaced their triangulation software.&lt;/p&gt;
&lt;h1&gt;Fourth year&lt;/h1&gt;
&lt;p&gt;The courses from the previous years were all mandatory, with the exception of some extra courses I took, but for the 4th and 5th year I could choose my own profile and what courses to take. I spent quite a lot of time thinking about which courses I wanted to take. In the end I’m quite happy with my selection but there are many interesting courses I had to say no to. The main profile I targeted was the &lt;a href=&quot;https://www.ida.liu.se/edu/ugrad/program/profiler/pal/index.sv.shtml&quot;&gt;Programming and Algorithms&lt;/a&gt; profile.&lt;/p&gt;
&lt;p&gt;In hindsight these are my favourite courses during the year:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TDDD48 Automated Planning&lt;/li&gt;
&lt;li&gt;AAPS Advanced Algorithmic Problem Solving&lt;/li&gt;
&lt;li&gt;TDDB44 Compiler Construction&lt;/li&gt;
&lt;li&gt;TATA54 Number Theory&lt;/li&gt;
&lt;li&gt;TDDC17 Artificial Intelligence&lt;/li&gt;
&lt;li&gt;TDDD56 Multicore and GPU Computing&lt;/li&gt;
&lt;li&gt;TDDA69 Data and Program Structures (&lt;a href=&quot;https://mitpress.mit.edu/sicp/full-text/book/book.html&quot;&gt;SICP&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I didn’t find the compiler course &lt;em&gt;as&lt;/em&gt; fun as I had initially thought. The theory part wasn’t very interesting but the lab part was really, really good! All in all it still was a very fun course. The AI courses (Automated Planning and Artificial Intelligence) were great and AI is an area I’m very interested in. During this time I also took an &lt;a href=&quot;https://www.coursera.org/learn/machine-learning&quot;&gt;online course in Machine Learning&lt;/a&gt; via Coursera by Stanford University. Number Theory is another maybe niche area in mathematics which I found interesting.&lt;/p&gt;
&lt;p&gt;I continued doing some programming competitions as can be seen in &lt;a href=&quot;http://uhunt.felix-halim.net/id/115705&quot;&gt;UVa&lt;/a&gt; which enabled my to go to &lt;a href=&quot;http://2013.nwerc.eu/&quot;&gt;NWERC 2013&lt;/a&gt; in the Netherlands. Ultimately I’m not super good at these competitions but it was still a great experience. Netherlands (or specifically Delft) was great. In the Multicore and GPU Computing course there was a parallel sorting contest which I and my lab partner managed to win. The goal was to create a sorting routine on the CPU with the best sorting performance. Oh and I also went through the classic book Structure and Interpretation of Computer Programs or &lt;a href=&quot;https://mitpress.mit.edu/sicp/full-text/book/book.html&quot;&gt;SICP&lt;/a&gt; in a course. Very excellent book!&lt;/p&gt;
&lt;p&gt;During the summer I also took part in &lt;a href=&quot;/blog/2014/10/06/ida_summer_of_code_2014_summary/&quot;&gt;IDA Summer of Code 2014&lt;/a&gt; where I contributed to &lt;a href=&quot;https://github.com/rust-lang/rust&quot;&gt;rust&lt;/a&gt;. I also had my &lt;a href=&quot;/blog/2014/07/13/summer_job_at_configura/&quot;&gt;second summer job at Configura&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/configura14/octree2.png&quot; /&gt;
&lt;figcaption&gt;Our octree implementation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Fifth year&lt;/h1&gt;
&lt;p&gt;At the end of my fourth year I had grown a bit study tired. I had thought the summer jobs would have helped a bit but although the summer jobs were amazing it might have been better to take a bit of a holiday, which I did not do at all.&lt;/p&gt;
&lt;p&gt;But the real issue wasn’t me getting sick of studying, although I was a bit unmotivated, but I was fast approaching a burnout. It never got so serious that I became apathetic but it was pretty bad for a while. The last semester in my 4th year I only did 27 hp (30 hp is the target value) and the first semester in my 5th year I only managed 24 hp. I had accumulated extra points so I finished the university with 308.5 hp, of the required 30 hp, but I was less effective the last 1.5 year or so than usual.&lt;/p&gt;
&lt;p&gt;I might write more about my burnout in another post, but I did three main things to get out of it. The first thing I did was to start CBT (Cognitive Behavioral Therapy or Kognitiv beteendeterapi in Swedish). The second was to continue with things which made me happy and more importantly gave me more energy. Basically I started exercising more regularly. And the third thing I did was to scale down on my ambitions and focus on taking care of myself, this is the reason I didn’t study 100% the first semester.&lt;/p&gt;
&lt;p&gt;In the end I think I managed to get rid of the worst effects of the burnout and I managed to finish my studies. I was also a mentor in discrete math for a fourth time. I didn’t complete a ton of courses as the whole last semester was spent on writing my &lt;a href=&quot;/masters_thesis/&quot; title=&quot;My Master&amp;#39;s thesis&quot;&gt;Master’s thesis&lt;/a&gt; but I did complete a great course in cryptology and one about logic programming in Prolog.&lt;/p&gt;
&lt;p&gt;The cryptology course was especially good as it even introduced &lt;a href=&quot;https://bitcoin.org/en/&quot; title=&quot;Bitcoin&quot;&gt;Bitcoin&lt;/a&gt; and the way the blockchain worked. Big kudos to that! I was aware of Bitcoin before but I wasn’t aware of the implementation details.&lt;/p&gt;
&lt;h1&gt;All courses&lt;/h1&gt;
&lt;p&gt;For reference this is the list of courses I completed. It surprises me at least to see how much I’ve actually done these years.&lt;/p&gt;
&lt;p&gt;I started two extra courses which I never finished:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TAMS15   Mathematical Statistics, first course&lt;/li&gt;
&lt;li&gt;TATA49   Geometry with Applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The statistics course was started during my first year, but I finished a similar in my later years and the geometry course was taken as a fun extra course but I later decided to skip it.&lt;/p&gt;
&lt;h2&gt;First year&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;TATA41   Calculus in One Variable 1&lt;/li&gt;
&lt;li&gt;TATA42   Calculus in One Variable 2&lt;/li&gt;
&lt;li&gt;TATA65   Discrete Mathematics&lt;/li&gt;
&lt;li&gt;TDDC10   Perspectives to Computer Technology&lt;/li&gt;
&lt;li&gt;TDDC66   Computer Systems and Programming&lt;/li&gt;
&lt;li&gt;TDDC67   Functional Programming and Lisp&lt;/li&gt;
&lt;li&gt;TDDC68   Imperative Programming and Ada&lt;/li&gt;
&lt;li&gt;TSEA22   Switching Theory and Logical Design&lt;/li&gt;
&lt;li&gt;TSTE58   Electronics&lt;/li&gt;
&lt;li&gt;TTIT02   Foundation Course in Mathematics&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Second year&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;TAOP33   Combinatorial Optimization, Introductory Course&lt;/li&gt;
&lt;li&gt;TATA24   Linear Algebra&lt;/li&gt;
&lt;li&gt;TATA53   Linear Algebra, Honours Course&lt;/li&gt;
&lt;li&gt;TATA61   Multivariable and Vector Calculus&lt;/li&gt;
&lt;li&gt;TDDC36   Logic&lt;/li&gt;
&lt;li&gt;TDDC69   Object Oriented Programming and Java&lt;/li&gt;
&lt;li&gt;TDDC70   Data Structures and Algorithms&lt;/li&gt;
&lt;li&gt;TDDD60   Interactive Systems&lt;/li&gt;
&lt;li&gt;TFYY68   Engineering Mechanics&lt;/li&gt;
&lt;li&gt;TSEA43   Digital Project Laboratory&lt;/li&gt;
&lt;li&gt;TSEA47   Computer Hardware and Architecture, part 1&lt;/li&gt;
&lt;li&gt;TSEA49   Computer Hardware and Architecture, part 2&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Third year&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;TAMS27   Mathematical Statistics&lt;/li&gt;
&lt;li&gt;TATA50   Transform Theory&lt;/li&gt;
&lt;li&gt;TATA64   Graph Theory&lt;/li&gt;
&lt;li&gt;TDDB68   Concurrent Programming and Operating Systems&lt;/li&gt;
&lt;li&gt;TDDC93   Software Engineering Theory&lt;/li&gt;
&lt;li&gt;TDDD09   Software Engineering Project&lt;/li&gt;
&lt;li&gt;TEIO27   Technology Based Entrepreneurship&lt;/li&gt;
&lt;li&gt;TFYA68   Physics&lt;/li&gt;
&lt;li&gt;TGTU50   Visits to Industry&lt;/li&gt;
&lt;li&gt;TSDT18   Signals and Systems&lt;/li&gt;
&lt;li&gt;TSEA29   Microcomputer, Project Laboratory&lt;/li&gt;
&lt;li&gt;TSKS10   Signals, Information and Communication&lt;/li&gt;
&lt;li&gt;TSRT12   Automatic Control Y&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fourth year&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;TANA09   Numerical Algorithms in Computer Science&lt;/li&gt;
&lt;li&gt;TATA54   Number Theory&lt;/li&gt;
&lt;li&gt;TD1077   Advanced Algorithmic Problem Solving&lt;/li&gt;
&lt;li&gt;TDDA69   Data and Program Structures&lt;/li&gt;
&lt;li&gt;TDDB44   Compiler Construction&lt;/li&gt;
&lt;li&gt;TDDC17   Artificial Intelligence&lt;/li&gt;
&lt;li&gt;TDDD14   Formal Languages and Automata Theory&lt;/li&gt;
&lt;li&gt;TDDD20   Design and Analysis of Algorithms&lt;/li&gt;
&lt;li&gt;TDDD48   Automated Planning&lt;/li&gt;
&lt;li&gt;TDDD56   Multicore and GPU Computing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fifth year&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;TDDD08   Logic Programming&lt;/li&gt;
&lt;li&gt;TDDD38   Advanced Programming in C++&lt;/li&gt;
&lt;li&gt;TGTU49   History of Technology&lt;/li&gt;
&lt;li&gt;TQDT33   Degree Project - Master’s Thesis&lt;/li&gt;
&lt;li&gt;TSIT03   Cryptology&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>Failed mime type for Krita</title><id>http://jonashietala.se/blog/2015/07/08/failed_mime_type_for_krita/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/07/08/failed_mime_type_for_krita" rel="alternate"/><published>2015-07-08T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I thought &lt;a href=&quot;https://krita.org/&quot; title=&quot;Krita Digital Painting&quot;&gt;Krita&lt;/a&gt; worked fine… Until I tried to save. Krita crashed whenever I tried to save (or open) a file and gave the error:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Could not find mime type &quot;application/x-krita&quot;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Turns out if you reinstall the package &lt;code&gt;shared-mime-info&lt;/code&gt; which comes natively with Slackware the problem goes away.&lt;/p&gt;
</content></entry><entry><title>Offset coordinates in Krita with Xinerama</title><id>http://jonashietala.se/blog/2015/07/05/offset_coordinates_in_krita_with_xinerama/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/07/05/offset_coordinates_in_krita_with_xinerama" rel="alternate"/><published>2015-07-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I recently bought an &lt;a href=&quot;http://www.wacom.com/en-us/products/pen-tablets/intuos-manga&quot; title=&quot;Intuos Manga drawing tablet&quot;&gt;Intuos Manga&lt;/a&gt; drawing tablet recently, because I got this fix idea that I want to learn how to draw. And what better way to do it than with a drawing tablet, while satisfying my need for new things?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/galleryimage2IntuousManga.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;With little experience I boldly set forth and I found a lovely and free drawing program &lt;a href=&quot;https://krita.org/&quot; title=&quot;Krita Digital Painting&quot;&gt;Krita&lt;/a&gt;. I’ve used photoshop earlier but it’s just so expensive and &lt;a href=&quot;https://krita.org/&quot; title=&quot;Krita Digital Painting&quot;&gt;Krita&lt;/a&gt; seems like a good replacement. &lt;a href=&quot;https://inkscape.org/en/&quot; title=&quot;Inkscape&quot;&gt;Inkscape&lt;/a&gt; is another good alternative for vector graphics.&lt;/p&gt;
&lt;p&gt;To install &lt;a href=&quot;https://krita.org/&quot; title=&quot;Krita Digital Painting&quot;&gt;Krita&lt;/a&gt; you need KDE, which should come preinstalled with Slackware. If you’re like me and decided to skip it you can install it with&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;slackpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install kde&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I had some trouble installing &lt;a href=&quot;https://krita.org/&quot; title=&quot;Krita Digital Painting&quot;&gt;Krita&lt;/a&gt;, but ultimately &lt;a href=&quot;http://www.davidrevoy.com/article193/guide-building-krita-on-linux-for-cats&quot; title=&quot;Install Krita&quot;&gt;this guide with cats&lt;/a&gt; worked when I also changed &lt;code&gt;krita/plugins/formats/tiff/kis_tiff_converter.cc&lt;/code&gt; from&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;C&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight C&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor c&quot;&gt;&lt;span class=&quot;keyword control import c&quot;&gt;#if&lt;/span&gt; TIFFLIB_VERSION &amp;lt; 20111221
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;tmsize_t&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta preprocessor c&quot;&gt;&lt;span class=&quot;keyword control import c&quot;&gt;#endif&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;C&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight C&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type c&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;support type sys-types c&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;entity name type typedef c&quot;&gt;tmsize_t&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which I filed as a bug report over at KDE.&lt;/p&gt;
&lt;p&gt;More troubling was the fact that drawing on the canvass was offset using dual screens with Xinerama. It worked fine in both Inkscape and Gimp and even on the gui controls. The problem went away if I switched to only a single screen. Now &lt;a href=&quot;https://bugzilla.gnome.org/show_bug.cgi?id=634977&quot; title=&quot;Krita dualscreen bug 1&quot;&gt;this&lt;/a&gt; &lt;a href=&quot;https://bugzilla.gnome.org/show_bug.cgi?id=66813&quot; title=&quot;Krita dualscreen bug 2&quot;&gt;is&lt;/a&gt; &lt;a href=&quot;https://forum.kde.org/viewtopic.php?f=139&amp;amp;t=120228&quot; title=&quot;Krita dualscreen bug 3&quot;&gt;a&lt;/a&gt; &lt;a href=&quot;https://bugs.kde.org/show_bug.cgi?id=298144&quot; title=&quot;Krita dualscreen bug 4&quot;&gt;common&lt;/a&gt; &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?id=142144&quot; title=&quot;Krita dualscreen bug 5&quot;&gt;problem&lt;/a&gt; &lt;a href=&quot;https://bugs.launchpad.net/ubuntu/+source/wacom-tools/+bug/301075&quot; title=&quot;Krita dualscreen bug 6&quot;&gt;with&lt;/a&gt; Xinerama and Krita.&lt;/p&gt;
&lt;p&gt;I did not manage to solve it using Xinerama, the bug is still unfixed. It works perfectly if instead of Xinerama RandR is used to setup the dual screen layout. I managed to set it up thanks to the &lt;a href=&quot;https://wiki.archlinux.org/index.php/Xrandr&quot; title=&quot;Xrandr&quot;&gt;excellent arch linux wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The final result for me is to add this to &lt;code&gt;.xinitrc&lt;/code&gt; and use a simple &lt;code&gt;xorg.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;xrandr&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;output&lt;/span&gt; DVI-I-3&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;mode&lt;/span&gt; 1920x1080&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;pos&lt;/span&gt; 0x0&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;rotate&lt;/span&gt; left&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;output&lt;/span&gt; DVI-I-2&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;mode&lt;/span&gt; 1920x1080&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;pos&lt;/span&gt; 1080x480&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And Krita (and Inkspace, Gimp, …) works perfectly.&lt;/p&gt;
&lt;p&gt;My full workspace setup is &lt;a href=&quot;https://github.com/treeman/dotfiles/tree/master/.workspace&quot; title=&quot;Workspace dotfiles&quot;&gt;on github&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><title>Netrunner Spring Tournament</title><id>http://jonashietala.se/blog/2015/05/04/netrunner_spring_tournament/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/05/04/netrunner_spring_tournament" rel="alternate"/><published>2015-05-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;There was another, smaller, netrunner tournament about a week ago. I was looking forward to a very casual setting but there were also some guys who came from… Västerås I think, but I’m not sure. We managed to scrape together 9 people at least, and I didn’t notice anyone bringing anything super janky.&lt;/p&gt;
&lt;p&gt;Runner is my Achilles Heel and so I decided not to make any big changes, I brought a more aggressive &lt;a href=&quot;http://netrunnerdb.com/en/decklist/20181/waltzing-away-spring-tournament-2nd&quot; title=&quot;Runner deck: Waltzing Away?&quot;&gt;Leela deck&lt;/a&gt; with desperado and security testing. I know it &lt;em&gt;should&lt;/em&gt; be a good deck as other people has won many tournaments with variations of it, but I’m feeling a bit less confident with it anyway.&lt;/p&gt;
&lt;p&gt;My corp deck is a &lt;a href=&quot;http://netrunnerdb.com/en/decklist/20182/industrial-awesomeness-spring-tournament-2nd&quot; title=&quot;Corp deck: Industrail Awesomeness&quot;&gt;super fun deck&lt;/a&gt; with Industrial Genomics which had performed very well during testing but I’m still worried. My feeling is that it’s still the most janky corp deck in the tournament.&lt;/p&gt;
&lt;p&gt;The tournament format is a simple swiss, with no playoffs.&lt;/p&gt;
&lt;h2&gt;Match 1, Bye&lt;/h2&gt;
&lt;p&gt;I came here to play netrunner, not to watch other people play netrunner… The 1 hour wait was quite boring to be honest.&lt;/p&gt;
&lt;p&gt;4 points and I’m the lead! It feels sad though.&lt;/p&gt;
&lt;h2&gt;Match 2, Henrik Etf/Kate&lt;/h2&gt;
&lt;p&gt;vs Engineering the Future&lt;/p&gt;
&lt;p&gt;So I play my friend Henrik again. I know his decks inside out, and he knows mine. It’s a bit fuzzy, but I don’t think I got a super terrible start. I try to keep his money low, but failing. I try to get some accesses, but I find nothing. He scores and I bounce and try to put some pressure but I fail. Somehow I’m locked out of all servers without any money and I lose 0-7.&lt;/p&gt;
&lt;p&gt;Well played Henrik, well played. Still 4 points.&lt;/p&gt;
&lt;p&gt;vs Kate&lt;/p&gt;
&lt;p&gt;So I get set up and I get my money rolling. I score out an NAPD and a Fetal I believe, but we’re a bit low on time. I score some agendas and he’s finding nothing. He has a fairly good rig out, but he can’t get anywhere fast. But time is called and I win on time.&lt;/p&gt;
&lt;p&gt;Time is my biggest enemy. 5 points.&lt;/p&gt;
&lt;h2&gt;Match 3, Fredrik NEH/Leela&lt;/h2&gt;
&lt;p&gt;vs Leela&lt;/p&gt;
&lt;p&gt;Ah my trusty corp matchup. I’m in control the whole game and I get my asset economy set up. He makes the mistake of not trashing anything or running archives so I manage to get rich as a troll. He’s richer for a time with ~40 credits from clicking Kati every turn, but it doesn’t really matter when I rezz 2x Ashigaru on HQ and Tollbooth/Susanoo/Tsurugi on my scoring server, naturally with Ash or Caprice for protection.&lt;/p&gt;
&lt;p&gt;I can score out quite comfortably. 7 points!&lt;/p&gt;
&lt;p&gt;vs Near-Earth Hub&lt;/p&gt;
&lt;p&gt;This is another one of these runner games where I have no idea what I’m doing wrong, but I’m severely locked out, without any money and the corp just crushes me.&lt;/p&gt;
&lt;p&gt;The start is quite bad, no desperado and no security testing leaves me quite poor. He’s got 2 pieces of ice in front of HQ, the outermost unrezzed, I have some breakers and a little bit of money and I gamble with a Legwork but he rezzes a Tollbooth. Drats. I knew he had at least a Beale but also an Astroscript he scores out. This was a huge misplay, I should have either built up or focused on trashing his assets.&lt;/p&gt;
&lt;p&gt;In the end the astrotrain rolled me quite hard with 3 astroscripts scores in rapid succession. I knew I should have built a shaper/anarch with Clot. Still 7 points.&lt;/p&gt;
&lt;h2&gt;Match 4, Harald Etf/Hayley&lt;/h2&gt;
&lt;p&gt;vs Hayley&lt;/p&gt;
&lt;p&gt;A stealth Hayley deck. As against Fredrik I get my asset economy online but he’s pressuring my R&amp;amp;D a lot harder, luckily not finding anything. To combat stealth I stack sentries like a madman with 2x Cortex Lock and one Tsurugi over R&amp;amp;D and Susanoo and another Tsurugi over my scoring server. The tax is very real, both in credits and in clicks via net damage. I score out a couple of agendas and I’m ready to score out for the win, but the game ends after a desperation run on R&amp;amp;D with only 2 cards left - and a Snare.&lt;/p&gt;
&lt;p&gt;Corp deck is fantastic, although I need to play it a bit faster. 9 points.&lt;/p&gt;
&lt;p&gt;vs Engineering the Future&lt;/p&gt;
&lt;p&gt;Finally I’m having a good start! I score an early agenda and add some pressure. He forces a score and I bounce ice on HQ and Account Siphons him down. I’m very much about to win, but my mortal enemy the time has decided to come visit me again, and I get a timed win.&lt;/p&gt;
&lt;p&gt;Now this is how the feeling of playing runner should be! 10 points.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;It seems I wasn’t the only one having trouble with running, as 22 victories came from the corps (15 AP, 3 flatlines, 4 timed) compared to the 10 runner victories (9 AP, 1 timed).&lt;/p&gt;
&lt;p&gt;Anyways it appears like I did fairly well, even though the bye gave me a huge point boost and my 2nd place feels quite undeserved.  Here are the final standings:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/standings_netrunner150425.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;I never played Daniel, but it appears he crushed everyone this day. Well done!&lt;/p&gt;
&lt;p&gt;While I didn’t win and I missed out on the playmat, I did get alt-arts of both Popup-window and Gordian Blade. Mmmh pretty! I especially like the popup-window art!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/gordian_popup_altarts.jpg&quot; /&gt;
&lt;/figure&gt;</content></entry><entry><title>Geekhack Toxic</title><id>http://jonashietala.se/blog/2015/04/09/geekhack_toxic/index.html</id><updated>2024-06-18T23:45:11+00:00</updated><link href="https://www.jonashietala.se/blog/2015/04/09/geekhack_toxic" rel="alternate"/><published>2015-04-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I came back to Linköping yesterday and I had a package waiting for me to pick it up. What could it be?&lt;/p&gt;
&lt;p&gt;With a crummy mobile phone photo I give you my &lt;a href=&quot;https://geekhack.org/index.php?topic=55644.0&quot; title=&quot;TOXIC&quot;&gt;TOXIC keycaps&lt;/a&gt; mounted on my trusty old das keyboard:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/toxic.jpg&quot; /&gt;
&lt;figcaption&gt;Woooo&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If only my &lt;a href=&quot;https://geekhack.org/index.php?topic=41464.0&quot; title=&quot;GH60&quot;&gt;GH60&lt;/a&gt; could arrive some time this decade…&lt;/p&gt;
</content></entry><entry><title>CS:GO AWP Nerf</title><id>http://jonashietala.se/blog/2015/04/06/csgo_awp_nerf/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/04/06/csgo_awp_nerf" rel="alternate"/><published>2015-04-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;When this man opens his mouth, truth comes out.&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=rsFnJYJ2buU&quot;&gt;https://www.youtube.com/watch?v=rsFnJYJ2buU&lt;/a&gt;
&lt;p&gt;If I ever make a game and I want someone to balance it and I had the money, I would hire Thorin.&lt;/p&gt;
</content></entry><entry><title>Netrunner Lindhska Store Championship Örebro</title><id>http://jonashietala.se/blog/2015/04/02/netrunner_lindhska_store_championship_rebro/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/04/02/netrunner_lindhska_store_championship_rebro" rel="alternate"/><published>2015-04-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After the awesomeness during the &lt;a href=&quot;/blog/2015/02/24/my_first_netrunner_store_championship/&quot;&gt;previous store championship&lt;/a&gt;, I decided to go to the store championship at Lindhska Bokhandel in Örebro.&lt;/p&gt;
&lt;p&gt;I brought a modified version of the same corp I used the last time, a &lt;a href=&quot;http://netrunnerdb.com/en/decklist/18428/friendly-neighbours-lindhska-store-championship&quot;&gt;Blue Sun kill deck&lt;/a&gt; and a &lt;a href=&quot;http://netrunnerdb.com/en/decklist/18429/sucker-punch-lindhska-store-championship&quot;&gt;new runner&lt;/a&gt; with Leela Patel. See the links for cards and some card choices.&lt;/p&gt;
&lt;p&gt;The tournament was a 26-player one, at least that’s the number I heard, with 5 rounds of swiss followed by a double elimination bracket. 7 players from Linköping went, again I think but I’m not sure if that’s the correct number.&lt;/p&gt;
&lt;h1&gt;Swiss&lt;/h1&gt;
&lt;h2&gt;Match 1, Tennin/Reina&lt;/h2&gt;
&lt;p&gt;vs Tennin&lt;/p&gt;
&lt;p&gt;Memory is a bit fuzzy here. I think I got off to a good start, but somehow the corp stabilized and we went into a long slog of a game. For some reason the corp managed to score out before I could find the final agenda.&lt;/p&gt;
&lt;p&gt;It certainly felt like I could have won the game, but I’m not sure what I did wrong. Might be that I wasn’t comfortable with the deck and played too aggressively. 0-2&lt;/p&gt;
&lt;p&gt;vs Reina&lt;/p&gt;
&lt;p&gt;Again I don’t remember the specifics. We had very little time and I manage to score out an agenda, so I get a timed win.&lt;/p&gt;
&lt;p&gt;Still, corp felt great and I was in control, 1-2.&lt;/p&gt;
&lt;h2&gt;Match 2, RP/Chaos Theory&lt;/h2&gt;
&lt;p&gt;vs Replicating Perfection&lt;/p&gt;
&lt;p&gt;Ah RP. Actually the first time I’ve played against the id, but I had a pretty good idea of how to approach the game. I scored an early agenda but I’m slowly getting locked out. Then he makes a pretty big misplay - he flips a naked remote and he wants to score, but it’s Nisei MK II instead of a 3/2 agenda and now he’s flustered. I apologize and I score the Nisei and I remove the Enhanced Login Protocol.&lt;/p&gt;
&lt;p&gt;Still, he’s not out of the game. I run indexing but he hid a Jackson in a remote, stupid mistake! I manage to same old thing indexing again and I score another agenda and I place another agenda as the 5th card. I carefully count the cards and I manage to score the winning agenda, before being locked out of the game.&lt;/p&gt;
&lt;p&gt;The opponent said he’s only played a week… Still played pretty good I’m very glad for that victory. 3-2&lt;/p&gt;
&lt;p&gt;vs Chaos Theory&lt;/p&gt;
&lt;p&gt;Another quick corp game. Snare last click into scorch for a simple victory. His inexperienced lost him the game there.&lt;/p&gt;
&lt;p&gt;5-2 and feeling better.&lt;/p&gt;
&lt;h2&gt;Match 3, RP/MaxX&lt;/h2&gt;
&lt;p&gt;vs MaxX&lt;/p&gt;
&lt;p&gt;We’re 6 players from Linköping and 2 from Stockholm at the top. Sadly I’m facing David, also from Linköping and we’re on our way to knock each other down.&lt;/p&gt;
&lt;p&gt;The game is slow, very slow. I feel in control and take it slow and easy. Scoring some agendas when I get them, but not drawing all that much. MaxX runs out of cards and runs a Levy. Somehow he runs of cards again and I know I’ve won.&lt;/p&gt;
&lt;p&gt;I have no idea how this happened, but we actually went to time, during our first match! Maybe it really was an intense game or maybe I was just tired or hungry… But anyway it happened. I manage to set up a win-win scenario for me during my second-to-last turn. Either he lets me score out or he runs the remote and let me sea-source scorch him to death (he had a hand size of 3 due to an early Cerebral Overwriter). He cooses the second option.&lt;/p&gt;
&lt;p&gt;7-2&lt;/p&gt;
&lt;h2&gt;Match 4, NEH/Whizzard&lt;/h2&gt;
&lt;p&gt;vs Near-Earth Hub&lt;/p&gt;
&lt;p&gt;This was by far the most stressful/exciting game of the day for me. I get a bad hand and I mulligan… Into a much much worse hand. No economy, no nothing. The corp scores an early astroscript, this isn’t looking so good… I do something, I can’t remember, then he sets up  a remote with one advancement counter on. Curious, it’s probably an NAPD, but sadly I can’t get in and score so I’m gearing up for a next turn combo.&lt;/p&gt;
&lt;p&gt;Sadly, it’s a Project Beale, worth 3 points and he’s got an astroscript token. From bad to worse, much worse. I desperately run his hand and his remote. Oh no, he’s got a scorch on top of R&amp;amp;D and he’s got a Data Raven protecting HQ. Luckily I’ve got a plascrete so I go tag-me with a Legwork, finding nothing. He’s using Jackson to draw like mad.&lt;/p&gt;
&lt;p&gt;I run another Legwork with a same old thing through the Data Raven and I find two agendas and I get in some single-accesses on R&amp;amp;D. Lady luck isn’t smiling for long though as he draws and install-advance a remote. Surely an NAPD, which I’m too poor to get at.&lt;/p&gt;
&lt;p&gt;My only hope is R&amp;amp;D and I have two interfaces out so I can access 3 cards. If I can bounce the NAPD I might still have a chance. The first card is a.. NAPD which I can’t steal. The second is a Breaking News so I bounce the advanced card now sitting on 5 agenda points.&lt;/p&gt;
&lt;p&gt;I’m too poor to get the NAPD and the next turn I get Scorched to death.&lt;/p&gt;
&lt;p&gt;The game was practically over from the terrible start, but I almost managed to steal a win. I got praise from the opponent but I can’t stop but think that I should have had a few more credits for that NAPD…&lt;/p&gt;
&lt;p&gt;7-4, feeling the pain.&lt;/p&gt;
&lt;p&gt;vs Whizzard&lt;/p&gt;
&lt;p&gt;Another id I haven’t played against. He tried, and was successful for a while, with killing my oversighted curtain walls and keeping my economy low. But still, I managed to score out two the cleaners and putting more and more pressure as I gradually build up my economy lead. I think I hit a shattered remains as well.&lt;/p&gt;
&lt;p&gt;The game ends with me advancing the winning agenda, he tries but cannot access it or any other agenda, and I score for the win.&lt;/p&gt;
&lt;p&gt;Again corp is feeling absolutely great. 9-4&lt;/p&gt;
&lt;h2&gt;Match 5, EtF/Kate&lt;/h2&gt;
&lt;p&gt;This time I’m faced up against Henrik, my buddy from Linköping who knows my decks and I know his decks. Sadly it appears this is the battle for top 8.&lt;/p&gt;
&lt;p&gt;vs Engineering the Future&lt;/p&gt;
&lt;p&gt;During practice I felt very confident with my Leela deck and I get a great start scoring two 3/2 agendas. Not thinking more about it I try to build up a bit and getting ready to score the winning agenda as I know he has a few 5/3.&lt;/p&gt;
&lt;p&gt;But things are not shaping up that way. I try to keep is economy low but he manages to get two adonis campaigns up and running and he hits two large GRNLD Refineries. Probably a huge misplay by me to allow that to happen. With his economy up he gets some nice taxing servers up and my aggressive running has not paid off at all. He’s all set up and I practically have nothing.&lt;/p&gt;
&lt;p&gt;My last hope is an indexing through a Janus I know is there. By my counts I’m only 2 or 1 credit off from making two succesful runs through R&amp;amp;D in the hopes of scoring out, but it’s not meant to be. I’ve already accumulated 3 brain damage from previous (too aggressive) encounters.&lt;/p&gt;
&lt;p&gt;With great play he manages to score out and win. Well played. 9-6&lt;/p&gt;
&lt;p&gt;vs Kate&lt;/p&gt;
&lt;p&gt;Again I’m having difficulties to recall the specifics of the match. I know I managed to hit one shattered remains to stop his drip econ for a while. I manage to score an agenda but time is running out.&lt;/p&gt;
&lt;p&gt;I have a 5/3 agenda which I’ve already advanced twice. I literary have my whole hand full of kill cards: 1 snare, 1 sea-source, 3 scorch and 2 punitives and with more money I’m just waiting for him to make a run. I decide to fake the agenda as the almighty 9/6 Government Takeover agenda and I advance it up to 7 in the course of two turns. In hindsight it might have been better to score it out as a 5/3, but that’s not what I did.&lt;/p&gt;
&lt;p&gt;So sitting at 7 advancement counters Henrik decides to… Not run it! Instead he runs my hand twice, the second time he imps my sea-source. Sigh.&lt;/p&gt;
&lt;p&gt;So the game ends with me winning on time, somehow it feels a bit frustrating as I had so much control the whole game, thinking how can I loose? Turns out, with some bad luck and some good runner decisions it’s quite possible not to win.&lt;/p&gt;
&lt;p&gt;10-6.&lt;/p&gt;
&lt;h1&gt;The Cut&lt;/h1&gt;
&lt;p&gt;As Henrik and I had the battle for the last place into playoffs, which I lost, Henrik makes the cut on 11 points and we’re a bunch of other players with 10 points.  Huge congrats to Henrik as he really did play better than I did.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Once again I’m amazed by the friendliness of the Netrunner community. Everyone was really nice and friendly. I joked around a bit with some guys and girls I’ve never even met before, which is no small feat with a very shy and introvert person such as myself. I got a ride all the way from Linköping to Örebro and the guy with the other car even came and asked me if I wanted to come with him earlier as I got knocked out. As it happens I stayed and watched some of Henrik’s and Fredrik’s matches.&lt;/p&gt;
&lt;p&gt;As for the games themselves I’m super happy with my corp deck which practically went undefeated during the tournament. I felt quite comfortable to win both the games where I got a timed win from.&lt;/p&gt;
&lt;p&gt;The runner deck however I’m not super happy with. It felt slow and low on economy and just a bit awkward. Some of the problems can be attributed to good corp play: I didn’t land many good account siphons which made my economy quite bad and they played around Leela’s ability quite well. Ice up centrals at least twice and don’t score out agendas on the last click.&lt;/p&gt;
&lt;p&gt;But mostly I think I didn’t play the runner deck right, I wanted to play more aggressively than maybe you’re supposed to with a slower control deck such as the one I had made. I really need to try out a Leela build based on Desperado and an economy package with Dirty Laundry and Security Testing, I think it might fit my style better. I also want to play around more with the wonderful Anarchs…&lt;/p&gt;
&lt;p&gt;Looking forward to the next time I can play some Netrunner!&lt;/p&gt;
</content></entry><entry><title>My first netrunner store championship</title><id>http://jonashietala.se/blog/2015/02/24/my_first_netrunner_store_championship/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2015/02/24/my_first_netrunner_store_championship" rel="alternate"/><published>2015-02-24T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;My girlfriend has told me I get these narrow interests where I pour all my energy and thoughts into and about 1,5 months ago I discovered &lt;a href=&quot;https://boardgamegeek.com/boardgame/124742/android-netrunner&quot;&gt;Netrunner&lt;/a&gt;, a very awesome card game. Check out &lt;a href=&quot;https://www.youtube.com/watch?v=g3w0B7txipk&quot;&gt;this how to play&lt;/a&gt; or &lt;a href=&quot;https://www.youtube.com/user/CovenantTCG/videos&quot;&gt;team covenant’s channel&lt;/a&gt; if you want to know more.&lt;/p&gt;
&lt;p&gt;So this Sunday I went to my first store championship with Henrik, the one other player I’ve competitively played the game with. Well I’ve played 2 games with my girlfriend, a bunch (10-ish) with her little brother and a few with another friend of mine but there I’ve always been the one teaching the game and making the decks and Henrik was the one who taught me the game.&lt;/p&gt;
&lt;p&gt;I decided to bring a &lt;a href=&quot;http://netrunnerdb.com/en/decklist/16173/beginners-takeover-link-ping-store-champ-4th-place&quot;&gt;Blue Sun deck which tries to kill&lt;/a&gt; you and a &lt;a href=&quot;http://netrunnerdb.com/en/decklist/16178/destruction-link-ping-store-champ-4th-place&quot;&gt;prepaid MaxX deck&lt;/a&gt; I’ve been playing around with lately. The decks are very fun to play and I felt pretty good about them, but I certainly didn’t expect to get top 4, which I did!&lt;/p&gt;
&lt;p&gt;The tournament was a 12-player one with 4 rounds of swiss followed by a double elimination bracket.&lt;/p&gt;
&lt;h1&gt;Swiss&lt;/h1&gt;
&lt;p&gt;Swiss is played both as runner and corp and you get 2 points for each win with a 65 min time limit.&lt;/p&gt;
&lt;h2&gt;Match 1, NEH/Kate&lt;/h2&gt;
&lt;p&gt;vs Near-Earth Hub&lt;/p&gt;
&lt;p&gt;The tournament went off with a bang when I faced the tournament organizer and his self-proclaimed “fast deck”. True enough. I manage to snag an Astroscript early, femme the wraparound in front of HQ and I’m feeling good. However he’s got a ton of money, I’m poor, and he installs another Wraparound in front of HQ and I only have an eater and a femme and no Keyhole. He proceeds to rezz a SanSan and score out a Beale. I manage to trash the SanSan but he rezzes another one and scores an Astroscript. Basically over from there, 2-7 is the final score.&lt;/p&gt;
&lt;p&gt;I was a bit flustered as I had never played against a deck like this, only read about how horrible it was and it was indeed a bit horrible. 0-2.&lt;/p&gt;
&lt;p&gt;vs Kate&lt;/p&gt;
&lt;p&gt;I don’t remember very much of the game or what type his runner was, only that I got a remote up and install-advance-advance a The Cleaners. He does some things and thinks a bit. He decides to run the remote and scores, but he’s down to 3 cards. I proceed to Sea-Source Scorch for the win, with a Punitive on hand for extra overkill.&lt;/p&gt;
&lt;p&gt;2-2 in prestige and I’m feeling good, I managed to grab a win!&lt;/p&gt;
&lt;h2&gt;Match 2, Making News/Kate&lt;/h2&gt;
&lt;p&gt;vs Stealth Kate&lt;/p&gt;
&lt;p&gt;I feel pressured the whole game but manages to stabilize a bit. I had several agendas on hand the whole game but I install a snare in the remote hoping for a scoring window next turn. Turn before he ran into a Taurus in an empty remote (for Bank Job/Desperado money) and I trash Desperado and an R&amp;amp;D interface. But the runner doesn’t bite and goes for a Maker’s Eye on R&amp;amp;D, but hits a surprise Snare and dies with only 2 cards in hand.&lt;/p&gt;
&lt;p&gt;Things are going better than expected, the decks are performing pretty well. 4-2.&lt;/p&gt;
&lt;p&gt;vs Making News&lt;/p&gt;
&lt;p&gt;I saw the deck during the first match and I knew he ran a tag storm deck with some tag punishment. I play it safe and get an early Private Security Force in a naked remote. As the game goes on I manage to get my Keyhole/Eater combo up and I manage to mill two agendas into the archives and he has an NAPD scored. Sometime during the game he plays a Midseasons and gives me a ton of tags and trashes a same old thing and a hades shard, prolonging the game a bit.&lt;/p&gt;
&lt;p&gt;Later on he realizes it’s a misplay as you can only play it the turn after a runner scores an agenda (I didn’t even think about it). The judge says that makes it a default win for me, but we decide to play out the game just to see what happens. As it turns out I manage to win the turn after, so I consider it a fair win.&lt;/p&gt;
&lt;p&gt;I’m now up 6-2 and things are going much better than expected.&lt;/p&gt;
&lt;h2&gt;Match 3, Andromeda/HB&lt;/h2&gt;
&lt;p&gt;vs Andromeda&lt;/p&gt;
&lt;p&gt;We come back after lunch and I find myself on the top table, meaning I have one of the best scores so far! But now I’m playing a fairly standard Andromeda, the (apparently) most feared runner. But I dunno, I’ve never played her.&lt;/p&gt;
&lt;p&gt;I get a turn 1 housekeeping but for some reason I don’t play it immediately! No idea why I don’t, but at least I do it turn 2 and it messes him up a ton. Turn 2 I also have a Government Takeover and a punitive on hand and I decide to play the takeover in a remote. But then he decides to play a Crash Space the same turn and now my nerves are on the edge! Luckily he doesn’t run it and the game slows down a bit.&lt;/p&gt;
&lt;p&gt;Then I get a second punitive on hand and I decide to advance the takeover, hoping to entice him to run it. But still he doesn’t bite. Instead he manages to score an agenda from hand and now he can win by running the remote. He still has 3 cards on hand and I have 2 Punitives… I decide to use them to slow him down and to remove his Crash Space. He spends the next turn drawing cards and I can ice up the remote some more, possibly replacing or start advancing the Takeover.&lt;/p&gt;
&lt;p&gt;The game ends when he accesses a Snare on his second click. He removes the tag on his third but now he’s got two cards. For his fourth click he boldly proclaims “living on the edge!” and runs my HQ and scores another agenda. He’s now 6-0 but he’s down to two cards and another player comments “don’t die”. I promptly kill him the next turn with Punitive.&lt;/p&gt;
&lt;p&gt;Super tense and fun game! Now I’m 8-2 and things are going fantastic, my corp deck has pulled through like a boss.&lt;/p&gt;
&lt;p&gt;vs The Foundry&lt;/p&gt;
&lt;p&gt;Now I know he runs grail and I try to be super careful. I play it slow and I manage to get my keyhole/eater combo up and I’m getting a ton of cheap R&amp;amp;D access but I keep missing agendas. Still feeling good, I’m in control of the game and I have an agenda. He scores an Accelerated Beta Test and luckily for him he hits two ice and installs over archives and R&amp;amp;D. But I still have R&amp;amp;D access and can continue with the keyholes. I manage to mill 2 NAPD into archives.&lt;/p&gt;
&lt;p&gt;Then he rezzes a Will-o’-the-Wisp and my Eater is dead, my game is completely stomped. Locked out of archives and locked out of Retrieval Runs I feel the game is lost to me. I get a Mimic out and try for a remote access, but I run into a Merlin. He searches for another copy and reveals two Merlins in hand for a total of 6 damage, I have 5 cards on hand with one I’ve Had Worse. He draws 2 cards, nothing. He draws 2 more and the last card is I’ve Had Worse, I draw 3 more cards and I barely survive.&lt;/p&gt;
&lt;p&gt;When I finally get out my Eater out we’re running out of time. He installs something in a remote which I can’t access and archives is still expensive. If I had one more round I could money up and go for the archives, but now it feels like the game is over. Luckily it’s not an agenda in the remote. He draws another beta test and we both needed just another round.&lt;/p&gt;
&lt;p&gt;We draw the game and I’m now 9-3. Feeling good but high on adrenaline after two of the craziest games I’ve ever played!&lt;/p&gt;
&lt;h2&gt;Match 4, Valencia/Harmony Medtech&lt;/h2&gt;
&lt;p&gt;vs &lt;a href=&quot;http://netrunnerdb.com/en/decklist/16116/rush-winning-store-championship-deck&quot;&gt;Harmony Medtech rush&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Another identity I’ve never played, but now without any idea what I’m supposed to expect. Luckily I get set up fast and I manage to steal an early agenda. He’s having trouble finding agendas and I’m getting a ton of keyhole access. I find another agenda with keyhole and I’m feeling good, even though 2x tsurugi in front of archives are very taxing. He installs two cards in a remote server (and advances one I think?) protected by a guard and a lotus field but I destroy the ice, win the psi game and scores an NAPD for the win.&lt;/p&gt;
&lt;p&gt;I’m a little proud for accessing the face down first as I only had 4 credits on hand, instead of trashing the caprice only to have to leave the NAPD there. More experienced players might say it’s a given, but learning the rather large card pool isn’t that straightforward.&lt;/p&gt;
&lt;p&gt;Incredibly I’m 11-3, sitting on the top table and I think I have a good shot at top 4.&lt;/p&gt;
&lt;p&gt;vs &lt;a href=&quot;http://netrunnerdb.com/en/decklist/16112/cannot-control-yourself-winning-store-championship-deck&quot;&gt;Control Valencia&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Henrik also brought Valencia and I really considered to have Elizabeth Mills in the deck, but I cut her the day before. Perhaps I shouldn’t have.&lt;/p&gt;
&lt;p&gt;Playing a control Valencia I feel a bit shut down. The game goes long and I have 2x punitive. Runner is pressuring me with Itinerant Protesters and keeping me poor with account siphon. I had a window where the runner had 4 tags, I try to draw for the scorched win but I don’t find it. I’m poor most of the game but finally stabilize and get a Housekeeping up. I place Government Takeover in archives but runner doesn’t bite. I place a snare and a crap card in remotes and runner does 2x Blackmail, but clears tags and draws up. I see my chance and install-advance-advance a The Cleaners, but another Blackmail makes it a score for the runner. Out of tricks I loose to the later archive run.&lt;/p&gt;
&lt;p&gt;Probably some misplays, but I felt behind the whole game. Very strong deck, might reconsider ms Mills. 11-5.&lt;/p&gt;
&lt;h1&gt;Playoffs&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/standings_netrunner150222.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The top seed has 12 points and I’m second with 11 points. 2nd plays 3rd which means I’ll get a rematch of my last match.&lt;/p&gt;
&lt;h2&gt;Match 5, Harmony Medtech&lt;/h2&gt;
&lt;p&gt;Rematch time! I got to choose runner/corp and I went with runner as the game went very well the last time. This time however I don’t get the fast setup and he has an early remote which I can’t get into and the game is over quite quickly.&lt;/p&gt;
&lt;p&gt;6-0 is the final score and I feel a bit deflated.&lt;/p&gt;
&lt;h2&gt;Match 6, MaxX&lt;/h2&gt;
&lt;p&gt;Once again I get to choose sides. I’m a bit bummed over my runner from the last game so I pick my corp and he’s running… MaxX. Yoy!&lt;/p&gt;
&lt;p&gt;He runs more regular breakers with double D4v1d, which is very bad for me. He’s also keeping me poor, forcing me to rezz ice all over the place, and I’m missing most of my economy cards. When I do get my Oversights, he’s far richer than I am wih Kati/Liberated Accounts/Daily Casts.&lt;/p&gt;
&lt;p&gt;I do get my Janus, trying to trick him into it to kill his D4v1d counters and clicks, but he doesn’t bite. He scores a 3-pointer and the game goes long. I end up clicking for credits, trying to have enough money to protect my Government Takeover sitting in my hand while trying to drain his economy during runs. His Yog kills my Datapikes and I feel constrained.&lt;/p&gt;
&lt;p&gt;The game goes to time and I hear the judge call out “15 seconds”. I install-advance-advance a 3-pointer, judge calls time and he has one turn left and I have one more. If the game is a tie I will win as I’m the higher rank (he was 4th after swiss). I do have 2 Punitives on hand and 32 credits. But he has ~ 40 credits. He runs the server, I rezz some ice and he steals the agenda. I bounce the ice but I don’t have enough money to kill him so we go to time and he wins 6-0.&lt;/p&gt;
&lt;p&gt;I misplayed as I could have rezzed a Janus when he stole the first agenda, but I didn’t think I had enough money so I didn’t. If I did he would have spent the D4v1d counters and the rest of his clicks, possibly steal an agenda from HQ, and then I would have enough money for a kill (I think)! Also I should have placed Janus on a remote, in front of another big piece of ice. Probably also too passive play from my side, I might have had a scoring window when he only had a D4v1d out and a scored The Cleaners might have turned the tides.&lt;/p&gt;
&lt;p&gt;Still, that’s the end for me and I finish 4th.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I was fairly confident in my theory crafted decks (some limited testing) and they did perform above expectations. I won a cool playmat and had a very, very good time! All were very nice and friendly and I sure want to play some more netrunner.&lt;/p&gt;
</content></entry><entry><title>2014 in Review</title><id>http://jonashietala.se/blog/2014/12/31/2014_in_review/index.html</id><updated>2023-10-01T13:25:44+00:00</updated><link href="https://www.jonashietala.se/blog/2014/12/31/2014_in_review" rel="alternate"/><published>2014-12-31T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Previous reviews: &lt;a href=&quot;/blog/2011/01/06/2010_in_review/&quot; title=&quot;2010 in Review&quot;&gt;2010&lt;/a&gt;, &lt;a href=&quot;/blog/2012/01/04/2011_in_review/&quot; title=&quot;2011 in Review&quot;&gt;2011&lt;/a&gt;, &lt;a href=&quot;/blog/2012/12/31/2012_in_review/&quot; title=&quot;2012 in Review&quot;&gt;2012&lt;/a&gt; and &lt;a href=&quot;/blog/2014/01/04/2013_in_review/&quot; title=&quot;2013 in Review&quot;&gt;2013&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;2014 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Solved &lt;a href=&quot;http://uhunt.felix-halim.net/id/115705&quot; title=&quot;UVa&quot;&gt;73 UVa problems&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Won a turn in &lt;a href=&quot;http://www.ida.liu.se/projects/impa/new/results&quot; title=&quot;IMPA&quot;&gt;IMPA&lt;/a&gt; and solved a bunch of problems.&lt;/li&gt;
&lt;li&gt;Completed a &lt;a href=&quot;http://www.ida.liu.se/~frehe/aaps/&quot; title=&quot;AAPS&quot;&gt;doctorand course&lt;/a&gt; about algorithmic problem solving.&lt;/li&gt;
&lt;li&gt;Finished my 4 first years in University.&lt;/li&gt;
&lt;li&gt;Became a contributor to &lt;a href=&quot;https://github.com/rust-lang/rust&quot; title=&quot;rust github&quot;&gt;rust&lt;/a&gt; and became &lt;a href=&quot;https://github.com/rust-lang/rust/wiki/Doc-friends-of-the-tree#2014-07-22-jonas-hietala-treeman&quot; title=&quot;friend of the tree, rust&amp;#39;s tree&quot;&gt;a friend of the tree&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Completed the online course &lt;a href=&quot;https://www.coursera.org/course/ml&quot; title=&quot;Machine Learning at Coursera&quot;&gt;Machine Learning&lt;/a&gt; in Coursera.&lt;/li&gt;
&lt;li&gt;Entered &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=1895&quot; title=&quot;Ludum Dare 29: Mining Incorporated&quot;&gt;Ludum Dare 29&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Had an &lt;a href=&quot;/blog/2014/07/13/summer_job_at_configura/&quot; title=&quot;Summer job at Configura&quot;&gt;awesome summer job at Configura&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Entered &lt;a href=&quot;/blog/tags/ida_summer_of_code/&quot; title=&quot;IDA Summer of Code 2014&quot;&gt;IDA Summer of Code&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Wrote a lot of &lt;em&gt;Rust&lt;/em&gt; and &lt;em&gt;C++&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Wrote some &lt;em&gt;CM, Racket, Haskell, Lua, Prolog&lt;/em&gt; and probably something else.&lt;/li&gt;
&lt;li&gt;Made a &lt;a href=&quot;https://github.com/treeman/libtimeedit&quot; title=&quot;libtimeedit&quot;&gt;timeedit rust library&lt;/a&gt;, scheduling information for university.&lt;/li&gt;
&lt;li&gt;Made a &lt;a href=&quot;https://github.com/treeman/libhabitrpg&quot; title=&quot;libhabitrpg&quot;&gt;habitrpg rust library&lt;/a&gt;, fetching info from &lt;a href=&quot;https://habitrpg.com/&quot; title=&quot;habitrpg&quot;&gt;habitrpg&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Was a mentor in &lt;em&gt;Discrete Math&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Went to &lt;a href=&quot;http://dreamhack.se/&quot; title=&quot;Dreamhack&quot;&gt;Dreamhack&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2014 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Achieved 2-kup in Taekwon-do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Been mostly pain-free, well, better at least.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Been a kids trainer in Taekwon-do. Very rewarding.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Survived a couple of training camps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read &lt;a href=&quot;/blog/2014/12/31/2014_read_books/&quot; title=&quot;2014 Read Books&quot;&gt;20 books&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote &lt;a href=&quot;/archive&quot; title=&quot;My archive&quot;&gt;32 blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Played a touch of &lt;a href=&quot;http://en.wikipedia.org/wiki/Go_%28game%29&quot; title=&quot;Go&quot;&gt;Go&lt;/a&gt;, the boardgame.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Discovered &lt;a href=&quot;http://boardgamegeek.com/boardgame/31627/ticket-ride-nordic-countries&quot; title=&quot;Ticket to Ride: Nordic Countries&quot;&gt;Ticket to Ride: Nordic Countries&lt;/a&gt;, a nice boardgame.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Also played &lt;a href=&quot;http://boardgamegeek.com/boardgame/822/carcassonne&quot; title=&quot;Carcassone&quot;&gt;Carcassone&lt;/a&gt; another great boardgame.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Played some other boardgames.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read some manga and manwha.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Kingdom&lt;/em&gt; was the year’s highlight.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Got a few 12-win arena runs in &lt;a href=&quot;http://us.battle.net/en/int?r=hearthstone&quot; title=&quot;Hearthstone&quot;&gt;Hearthstone&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2014 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Did not complete &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=1895&quot; title=&quot;Ludum Dare 29: Mining Incorporated&quot;&gt;my Ludum Dare entry&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Did not start a hardware project.&lt;/li&gt;
&lt;li&gt;Got burnt out.&lt;/li&gt;
&lt;li&gt;Skipped an extra course in geometry and one in probability.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2015&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Take care of Veronica.&lt;/li&gt;
&lt;li&gt;Achieve 1-kup in Taekwon-do.&lt;/li&gt;
&lt;li&gt;Do more strength training.&lt;/li&gt;
&lt;li&gt;Do some more yoga.&lt;/li&gt;
&lt;li&gt;Participate in &lt;a href=&quot;http://www.ludumdare.com/&quot; title=&quot;Ludum Dare&quot;&gt;Ludum Dare&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Prettify the site.&lt;/li&gt;
&lt;li&gt;Code a lot.&lt;/li&gt;
&lt;li&gt;Read more books.&lt;/li&gt;
&lt;li&gt;Play some more boardgames.&lt;/li&gt;
&lt;li&gt;Complete the exjobb.&lt;/li&gt;
&lt;li&gt;Finish university studies.&lt;/li&gt;
&lt;li&gt;Get a job?&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>2014 Read Books</title><id>http://jonashietala.se/blog/2014/12/31/2014_read_books/index.html</id><updated>2023-10-01T13:25:19+00:00</updated><link href="https://www.jonashietala.se/blog/2014/12/31/2014_read_books" rel="alternate"/><published>2014-12-31T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;In total I read 20 books, which is 33% less than &lt;a href=&quot;/blog/2014/01/03/2013_read_books/&quot;&gt;last year&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Fiction&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;How to Be a Woman&lt;/strong&gt; - Catilin Moran&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Fun&lt;/em&gt;!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Kill Room&lt;/strong&gt; - Jeffery Deaver&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Song of Ice and Fire: Game of Thrones&lt;/strong&gt; - George R.R. Martin&lt;/p&gt;
&lt;p&gt;Reread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Song of Ice and Fire: A Clash of Kings&lt;/strong&gt; - George R.R. Martin&lt;/p&gt;
&lt;p&gt;Reread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Song of Ice and Fire: A Storm of Swords&lt;/strong&gt; - George R.R. Martin&lt;/p&gt;
&lt;p&gt;Reread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Song of Ice and Fire: A Fest for Crows&lt;/strong&gt; - George R.R. Martin&lt;/p&gt;
&lt;p&gt;Reread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The First Law: The Blade Itself&lt;/strong&gt; - Joe Abercrombie&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The First Law: Before They Are Hanged&lt;/strong&gt; - Joe Abercrombie&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The First Law: The Last Argument of Kings&lt;/strong&gt; - Joe Abercrombie&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Non-Fiction&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Power of Habit&lt;/strong&gt; - Charles Duhigg&lt;/p&gt;
&lt;p&gt;How habits work. Helped me get more productive.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;En Perfekt Natt&lt;/strong&gt; - Björn Jedensjö&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Elementary Number Theory&lt;/strong&gt; - Kenneth H. Rosen&lt;/p&gt;
&lt;p&gt;Course book. Fun subject.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Competitive Programming 3&lt;/strong&gt; - Steven &amp;amp; Felix Halim&lt;/p&gt;
&lt;p&gt;The ultimate reference to competitive programming. A lot about problem solving and algorithms. Very good. Used as course book as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://gameprogrammingpatterns.com/&quot; title=&quot;Game Programming Patterns&quot;&gt;Game Programming Patterns&lt;/a&gt;&lt;/strong&gt; - Bob Nystrom&lt;/p&gt;
&lt;p&gt;A very good read.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Structure and Interpretation of Computer Programs&lt;/strong&gt; - Gerald Jay Sussman, Hal Abelson&lt;/p&gt;
&lt;p&gt;The examples are what makes this book really shine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automated Planning&lt;/strong&gt; - Ghallab, Na, Traverso&lt;/p&gt;
&lt;p&gt;Course book. Subject very interesting, book a bit heavy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Drunkard’s Walk&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Interesting and eye opening.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Logic, Programming and Prolog (2ed)&lt;/strong&gt; - U. Nilsson and J. Maluszynski&lt;/p&gt;
&lt;p&gt;Couse book. A bit too theoretical for my taste.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Introduction to Cryptography with Coding Theory&lt;/strong&gt; - Wade Trappe, Lawrence C. Washingto&lt;/p&gt;
&lt;p&gt;Course book, quite good.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Shock of the Old&lt;/strong&gt; - David Edgerton&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Den skapande människan&lt;/strong&gt; - Staffan Hansson&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>A Christmas Game</title><id>http://jonashietala.se/blog/2014/12/26/a_christmas_game/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/12/26/a_christmas_game" rel="alternate"/><published>2014-12-26T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’m going through a bit of a boardgame stint, as I usually do during christmas time. I had exactly one thing on my wishlist for this christmas for my little brother: &lt;a href=&quot;http://boardgamegeek.com/boardgame/31627/ticket-ride-nordic-countries&quot; title=&quot;Ticket to Ride: Nordic Countries&quot;&gt;Ticket to Ride: Nordic Countries&lt;/a&gt;. Guess what? I got something from my wishlist!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ticket-to-ride-nordic.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;This was our 5th or 6th game (or something?) and it’s a nice piece of game! Much simpler than &lt;a href=&quot;http://boardgamegeek.com/boardgame/31260/agricola&quot; title=&quot;Agricola. An amazing board game.&quot;&gt;Agricola&lt;/a&gt; and &lt;a href=&quot;http://boardgamegeek.com/boardgame/120677/terra-mystica&quot; title=&quot;Terra Mystica&quot;&gt;Terra Mystica&lt;/a&gt; (our current favourites) but still with a healthy dose of decision making. It’s a fun and straightforward game.&lt;/p&gt;
</content></entry><entry><title>Extracting schedule information from timeedit</title><id>http://jonashietala.se/blog/2014/11/27/extracting_schedule_information_from_timeedit/index.html</id><updated>2026-04-27T11:09:42+00:00</updated><link href="https://www.jonashietala.se/blog/2014/11/27/extracting_schedule_information_from_timeedit" rel="alternate"/><published>2014-11-27T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;At LIU we use timeedit to track our schedules. Recently they updated their interface and improved some parts. It’s now possible to create a prenumeration of a collection of courses exported as &lt;code&gt;csv&lt;/code&gt; which can then be imported to other calendar apps. But they also started to obfuscate their urls.&lt;/p&gt;
&lt;p&gt;This is the schedule for a single course &lt;code&gt;TGTU49&lt;/code&gt; in the interval “now - 2015-01-17”:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://se.timeedit.net/web/liu/db1/schema/ri157XQQ519Z50Qv27045gZ6y7Y7206Q6Y45Y7.html&quot;&gt;https://se.timeedit.net/web/liu/db1/schema/ri157XQQ519Z50Qv27045gZ6y7Y7206Q6Y45Y7.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is for the courses &lt;code&gt;TGTU49&lt;/code&gt; and &lt;code&gt;TATA49&lt;/code&gt; in the same interval:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://se.timeedit.net/web/liu/db1/schema/ri15YXQ2519Z55Qv2X0457Q6y4Y120876Y45Y7gQ6076775Z7.html&quot;&gt;https://se.timeedit.net/web/liu/db1/schema/ri15YXQ2519Z55Qv2X0457Q6y4Y120876Y45Y7gQ6076775Z7.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There seem to be some logic behind the urls, but first, let’s look at how they handle search.&lt;/p&gt;
&lt;p&gt;Using firebug we can intercept the json requests when we click the search button at&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://se.timeedit.net/web/liu/db1/schema/ri1Q7.html&quot;&gt;https://se.timeedit.net/web/liu/db1/schema/ri1Q7.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We find a GET request to&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://se.timeedit.net/web/liu/db1/schema/objects.html?max=15&amp;amp;fr=t&amp;amp;partajax=t&amp;amp;im=f&amp;amp;sid=3&amp;amp;l=sv&amp;amp;search_text=TGTU49&amp;amp;types=219&amp;amp;fe=132.0&amp;amp;fe=115.20132,20141,20142&quot;&gt;https://se.timeedit.net/web/liu/db1/schema/objects.html?max=15&amp;amp;fr=t&amp;amp;partajax=t&amp;amp;im=f&amp;amp;sid=3&amp;amp;l=sv&amp;amp;search_text=TGTU49&amp;amp;types=219&amp;amp;fe=132.0&amp;amp;fe=115.20132,20141,20142&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;which has has some search results formatted as html:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;entity other attribute-name id html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta toc-list id html&quot;&gt;objectbasketitemX0&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;data-id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;363972.219&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;data-idonly&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;363972&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;data-type&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;219&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;data-name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;TGTU49, Teknikhistoria, 1, TGTU49 1445-1503 Valla&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;clickable2 searchObject   &lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline table html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline table html&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;entity other attribute-name id html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta toc-list id html&quot;&gt;table0&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;cellspacing&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;0&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;cellpadding&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;0&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;infotable infotablenormal&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline table html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline table html&quot;&gt;td&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;entity other attribute-name id html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta toc-list id html&quot;&gt;info0&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;infoboxtitle &lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      TGTU49, Teknikhistoria, 1, TGTU49 1445-1503 Valla
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;objectfieldsextrawrap&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline table html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline table html&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;cellspacing&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;0&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;objectfieldsextra&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag inline table html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline table html&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline table html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline table html&quot;&gt;td&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta tag inline table html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline table html&quot;&gt;tr&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline table html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline table html&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag block any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag block any html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;types=219&lt;/code&gt; means we’re searching for a course and if can change it to &lt;code&gt;types=205&lt;/code&gt; we can search for student groups instead. If we change &lt;code&gt;objects.html&lt;/code&gt; to &lt;code&gt;objects.json&lt;/code&gt; we even get a json response:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;json&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight json&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Kurskod&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;TGTU49&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Kursnamn&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Teknikhistoria&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Omgång&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;1&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Kurstillfälle&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;TGTU49 1445-1503 Valla&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;json looks much better and it’s a lot easier to parse, but unfortunately if we instead search for “TGTU” we only get one match but using html we get six. What’s worse, there’s a lot less information given with json. &lt;code&gt;data-id&lt;/code&gt; for example seems important as it’s the unique id signifying the course.&lt;/p&gt;
&lt;p&gt;As I’m writing this I tried &lt;code&gt;.txt&lt;/code&gt; as well and we get a much larger json response which contains &lt;code&gt;data-id&lt;/code&gt;, among other things.&lt;/p&gt;
&lt;p&gt;Investigating the page source in ta schedule page we find&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;html&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight html&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;entity other attribute-name class html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value class html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta class-name html&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;entity other attribute-name id html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value id html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;meta toc-list id html&quot;&gt;links_base&lt;/span&gt;&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;entity other attribute-name html&quot;&gt;data-base&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value html&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta attribute-with-value html&quot;&gt;&lt;span class=&quot;string quoted double html&quot;&gt;&lt;span class=&quot;punctuation definition string begin html&quot;&gt;&amp;quot;&lt;/span&gt;https://se.timeedit.net/web/liu/db1/schema/ri.html?h=t&lt;span class=&quot;constant character entity html&quot;&gt;&lt;span class=&quot;punctuation definition entity html&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;punctuation definition entity html&quot;&gt;;&lt;/span&gt;&lt;/span&gt;sid=3&lt;span class=&quot;constant character entity html&quot;&gt;&lt;span class=&quot;punctuation definition entity html&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;punctuation definition entity html&quot;&gt;;&lt;/span&gt;&lt;/span&gt;p=0.m%2C20150117.x&lt;span class=&quot;constant character entity html&quot;&gt;&lt;span class=&quot;punctuation definition entity html&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;punctuation definition entity html&quot;&gt;;&lt;/span&gt;&lt;/span&gt;objects=363730.219&lt;span class=&quot;constant character entity html&quot;&gt;&lt;span class=&quot;punctuation definition entity html&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;punctuation definition entity html&quot;&gt;;&lt;/span&gt;&lt;/span&gt;ox=0&lt;span class=&quot;constant character entity html&quot;&gt;&lt;span class=&quot;punctuation definition entity html&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;punctuation definition entity html&quot;&gt;;&lt;/span&gt;&lt;/span&gt;types=0&lt;span class=&quot;constant character entity html&quot;&gt;&lt;span class=&quot;punctuation definition entity html&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;punctuation definition entity html&quot;&gt;;&lt;/span&gt;&lt;/span&gt;fe=0&lt;span class=&quot;punctuation definition string end html&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta tag inline any html&quot;&gt;&lt;span class=&quot;punctuation definition tag begin html&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag inline any html&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end html&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which seems to suggest that we can send a request directly to &lt;a href=&quot;https://se.timeedit.net/web/liu/db1/schema/ri.html&quot;&gt;https://se.timeedit.net/web/liu/db1/schema/ri.html&lt;/a&gt; with url parameters.&lt;/p&gt;
&lt;p&gt;For example&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://se.timeedit.net/web/liu/db1/schema/ri.html?sid=3&amp;amp;p=140703-141231&amp;amp;objects=363972.219&quot;&gt;https://se.timeedit.net/web/liu/db1/schema/ri.html?sid=3&amp;amp;p=140703-141231&amp;amp;objects=363972.219&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Is a search for &lt;code&gt;TGTU49&lt;/code&gt; (data-id: 363972.219) between 2014-07-03 and 2014-12-31 and&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://se.timeedit.net/web/liu/db1/schema/ri.html?sid=3&amp;amp;p=140703-141231&amp;amp;objects=363972.219%2C363741.219&quot;&gt;https://se.timeedit.net/web/liu/db1/schema/ri.html?sid=3&amp;amp;p=140703-141231&amp;amp;objects=363972.219%2C363741.219&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;searches for &lt;code&gt;TGTU49&lt;/code&gt; (data-id: 363972.219) and &lt;code&gt;TATA49&lt;/code&gt; (data-id: 363741.219).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sid&lt;/code&gt; is an important flag here which specifies what information you’re interested in.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;sid               Information given
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;------------------------------------------------------
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;3                 Date Course Local Type Teacher Group
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;4                 Date Type Teacher Local
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;others            Date
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s a bunch of other parameters which we can simply ignore. This time if we replace &lt;code&gt;.html&lt;/code&gt; to &lt;code&gt;.json&lt;/code&gt; we get a nice json request:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;json&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight json&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;columnheaders&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Kurs&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Lokal&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Undervisningstyp&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Lärare&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Studentgrupp&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Fria grupper&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Information till student&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Studentförening&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;URL&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;info&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;reservationlimit&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;reservationcount&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;constant numeric json&quot;&gt;17&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;   &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;reservations&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;span class=&quot;meta structure dictionary json&quot;&gt;&lt;span class=&quot;punctuation section dictionary begin json&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;id&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;361731&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;startdate&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;2014-11-04&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;starttime&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;13:15&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;enddate&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;2014-11-04&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;endtime&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;15:00&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator dictionary pair json&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;         &lt;span class=&quot;meta structure dictionary key json&quot;&gt;&lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;columns&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta structure dictionary value json&quot;&gt;&lt;span class=&quot;punctuation separator dictionary key-value json&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta structure array json&quot;&gt;&lt;span class=&quot;punctuation section array begin json&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;TGTU49&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;KEY1&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Föreläsning&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;Dick Magnusson&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;KA3, EMM3, EL3, PRO2&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string quoted double json&quot;&gt;&lt;span class=&quot;punctuation definition string begin json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end json&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator array json&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;invalid illegal expected-array-separator json&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;invalid illegal expected-array-separator json&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;invalid illegal expected-array-separator json&quot;&gt;.&lt;/span&gt;  &lt;span class=&quot;punctuation section array end json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section dictionary end json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also get information formatted as &lt;code&gt;.txt&lt;/code&gt; and &lt;code&gt;.csv&lt;/code&gt;. For parsing purposes the best one should be json, as we can use rust’s &lt;a href=&quot;http://doc.rust-lang.org/serialize/json/&quot; title=&quot;rust json serialization doc&quot;&gt;json deriving&lt;/a&gt;, but then we need to create a bunch of structs. &lt;code&gt;.csv&lt;/code&gt; is actually very easy to parse and it looks like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;TimeEdit, Linköpings universitet
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&quot;TGTU49, Teknikhistoria, 1, TGTU49 1445-1503 Valla&quot;, 2014-07-03 - 2014-12-31 ,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Startdatum, Starttid, Slutdatum, Sluttid, Kurs, Lokal, Undervisningstyp, Lärare, Studentgrupp, Fria grupper, Information till student, Studentförening, URL
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;2014-11-04, 13:15, 2014-11-04, 15:00, TGTU49, KEY1, Föreläsning, Dick Magnusson, &quot;KA3, EMM3, EL3, PRO2&quot;, , , ,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is what I did. For a more stable library I should probably switch to json parsing, but there it is.&lt;/p&gt;
&lt;p&gt;I made a &lt;a href=&quot;https://github.com/treeman/libtimeedit&quot; title=&quot;3rd party api for timeedit&quot;&gt;rust crate&lt;/a&gt; which uses the outlined approach to retrieve scheduling information from timeedit. There’s a bunch of things I’m not supporting, but it’s enough for my needs. I made a simple &lt;a href=&quot;https://github.com/treeman/liuschema&quot; title=&quot;timeedit cli&quot;&gt;cli&lt;/a&gt; and integrated a &lt;code&gt;.schema&lt;/code&gt; command into my &lt;a href=&quot;https://codeberg.org/treeman/rustbot&quot; title=&quot;an irc bot in rust&quot;&gt;irc bot&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><title>Hearthstone on Wine</title><id>http://jonashietala.se/blog/2014/11/12/hearthstone_wine/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/11/12/hearthstone_wine" rel="alternate"/><published>2014-11-12T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I like &lt;a href=&quot;http://us.battle.net/hearthstone/en/&quot; title=&quot;Hearthstone&quot;&gt;Hearthstone&lt;/a&gt; and recently the next expansion &lt;a href=&quot;http://www.goblinsvsgnomes.com&quot; title=&quot;Goblins vs Gnomes&quot;&gt;Goblins vs Gnomes&lt;/a&gt; so I wanted to install and play it. It didn’t work in vanilla wine, with a “time out error”, but I found a &lt;a href=&quot;https://bugs.winehq.org/show_bug.cgi?id=36216&quot; title=&quot;Hearthstone fails to start, says the game timed out&quot;&gt;bug report&lt;/a&gt; which makes it work. Here’s a short summary:&lt;/p&gt;
&lt;p&gt;Get wine source from &lt;a href=&quot;http://wiki.winehq.org/GitWine&quot; title=&quot;Git Wine&quot;&gt;git&lt;/a&gt;. My version was &lt;code&gt;wine-1.7.30-121-g6fe4d9e&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Make &lt;code&gt;shlexec.patch&lt;/code&gt; inside the source directory&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;diff&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight diff&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta diff range unified&quot;&gt;&lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;meta toc-list line-number diff&quot;&gt;-, +,&lt;/span&gt; &lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt;&lt;/span&gt; 
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Revert &amp;quot;shell32: Use CREATE_NEW_CONSOLE when SEE_MASK_NOCONSOLE is omitted.&amp;quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    This reverts commit 2005be6dc92c0943ede01525cecad88f8e83c9c7.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta diff header from-file&quot;&gt;&lt;span class=&quot;punctuation definition from-file diff&quot;&gt;---&lt;/span&gt; a/dlls/shell32/shlexec.c	
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta diff header to-file&quot;&gt;&lt;span class=&quot;punctuation definition to-file diff&quot;&gt;+++&lt;/span&gt; a/dlls/shell32/shlexec.c	
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta diff range unified&quot;&gt;&lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;meta toc-list line-number diff&quot;&gt;-338,7 +338,7&lt;/span&gt; &lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt;&lt;/span&gt; static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     startup.dwFlags = STARTF_USESHOWWINDOW;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     startup.wShowWindow = psei-&amp;gt;nShow;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup deleted diff&quot;&gt;&lt;span class=&quot;punctuation definition deleted diff&quot;&gt;-&lt;/span&gt;    if (!(psei-&amp;gt;fMask &amp;amp; SEE_MASK_NO_CONSOLE))
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;    if (psei-&amp;gt;fMask &amp;amp; SEE_MASK_NO_CONSOLE)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;         dwCreationFlags |= CREATE_NEW_CONSOLE;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;     if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                        lpDirectory, &amp;amp;startup, &amp;amp;info))
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before &lt;code&gt;make&lt;/code&gt; run&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;patch&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;p1&lt;/span&gt; &lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;lt;&lt;/span&gt; shlexec.patch&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then do &lt;code&gt;make&lt;/code&gt; and &lt;code&gt;make install&lt;/code&gt; as normal and have fun with Hearthstone.&lt;/p&gt;
</content></entry><entry><title>Soda</title><id>http://jonashietala.se/blog/2014/10/21/soda/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/10/21/soda" rel="alternate"/><published>2014-10-21T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;These quotes are from &lt;a href=&quot;https://news.ycombinator.com/item?id=8488714&quot; title=&quot;Soda May Age You as Much as Smoking&quot;&gt;hacker news&lt;/a&gt; and I found them all too funny.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;It’s hard for me to understand the whole soda phenomenon in Canada and the US. Is it as addictive as cigarettes? Does it make you crave for more? Or it simply tastes so good that you can’t get enough of it? Why not eat a bunch of apples instead (if you don’t care about the amount of sugar you consume)? Wouldn’t they taste better?&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;What are you drinking instead of soda in your country?&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;uh, water?&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;Water? Like out of the toilet!? (From the movie &lt;a href=&quot;http://www.imdb.com/title/tt0387808/quotes?item=qt1722899&quot;&gt;idiocracy&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;</content></entry><entry><title>Friend of the Tree</title><id>http://jonashietala.se/blog/2014/10/08/friend_of_the_tree/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/10/08/friend_of_the_tree" rel="alternate"/><published>2014-10-08T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I just noticed I was recognized as a &lt;a href=&quot;https://github.com/rust-lang/rust/wiki/Doc-friends-of-the-tree#2014-07-22-jonas-hietala-treeman&quot; title=&quot;Friend of the tree&quot;&gt;friend of the tree&lt;/a&gt; in a weekly meeting by the &lt;a href=&quot;http://rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; team. It came during my documentation sprint during &lt;a href=&quot;/blog/tags/ida_summer_of_code/&quot; title=&quot;IDA Summer of Code&quot;&gt;IDA Summer of Code&lt;/a&gt; and I discovered it now, only two and a half month later. Still a very pleasant surprise!&lt;/p&gt;
</content></entry><entry><title>IDA Summer of Code 2014: Summary</title><id>http://jonashietala.se/blog/2014/10/06/ida_summer_of_code_2014_summary/index.html</id><updated>2023-10-01T08:35:05+00:00</updated><link href="https://www.jonashietala.se/blog/2014/10/06/ida_summer_of_code_2014_summary" rel="alternate"/><published>2014-10-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is a wrap-up post of my entry to &lt;a href=&quot;/blog/2014/06/11/isoc&quot; title=&quot;IDA Summer of Code&quot;&gt;IDA Summer of Code&lt;/a&gt; this year.&lt;/p&gt;
&lt;h1&gt;Quick stats&lt;/h1&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;65 merged commits
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;6790 lines added
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;2822 lines deleted
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;36 pull requests, 34 merged
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;12 pull requests directly fixing issues
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;rest either documentation or cleanup
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;1 RFC submitted (postponed)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Worked ~160 hours
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Initial work&lt;/h1&gt;
&lt;p&gt;Before this summer I had never contributed anything to open source. Inspired by the &lt;a href=&quot;http://words.steveklabnik.com/how-to-be-an-open-source-gardener&quot;&gt;open source gardener&lt;/a&gt; my first steps was to read through &lt;em&gt;all&lt;/em&gt; issues labeled &lt;code&gt;A-doc&lt;/code&gt;, &lt;code&gt;E-easy&lt;/code&gt;, &lt;code&gt;E-mentor&lt;/code&gt; and &lt;code&gt;I-papercut&lt;/code&gt; mainly to find some easy issues I could work with. &lt;a href=&quot;https://github.com/rust-lang/rust/issues/15780&quot; title=&quot;rust issue #15780&quot;&gt;Issue #15780&lt;/a&gt; was for example the first issue I fixed. Before fixing issues it’s good to read through information for contributors, see for example &lt;a href=&quot;https://github.com/rust-lang/rust-guidelines&quot; title=&quot;rust guidelines&quot;&gt;rust guidelines&lt;/a&gt;, &lt;a href=&quot;https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md&quot; title=&quot;rust contributing&quot;&gt;contributing&lt;/a&gt; and &lt;a href=&quot;https://github.com/rust-lang/rust/wiki/Note-development-policy&quot; title=&quot;rust development policy&quot;&gt;development policy&lt;/a&gt; but there may be more scattered about.&lt;/p&gt;
&lt;p&gt;I contacted Steve Klabnik, who wrote the &lt;a href=&quot;http://words.steveklabnik.com/how-to-be-an-open-source-gardener&quot;&gt;open source gardener&lt;/a&gt; and who’s &lt;a href=&quot;http://words.steveklabnik.com/rusts-documentation-is-about-to-drastically-improve&quot; title=&quot;steveklabnik rust documentation&quot;&gt;been hired by Mozilla to work on rust&lt;/a&gt; and asked how I best could contribute and he thought documentation was an excellent way to contribute. I had also heard that documentation was low-hanging fruit so I figured it was a good way to start.&lt;/p&gt;
&lt;h1&gt;Documentation&lt;/h1&gt;
&lt;p&gt;The approach I took with documentation was to pick a part of the standard library, specifically &lt;a href=&quot;http://doc.rust-lang.org/collections/index.html&quot; title=&quot;rust std::collections&quot;&gt;collections&lt;/a&gt;, and I wanted to make sure everything had runnable examples. Personally the most useful thing when learning a new language is examples.&lt;/p&gt;
&lt;p&gt;For example &lt;a href=&quot;http://doc.rust-lang.org/collections/vec/struct.Vec.html#method.as_mut_ptr&quot; title=&quot;Vec::as_mut_ptr&quot;&gt;&lt;code&gt;Vec::as_mut_ptr&lt;/code&gt;&lt;/a&gt; has the type signature &lt;code&gt;fn as_mut_ptr(&amp;amp;mut self) -&amp;gt; *mut T&lt;/code&gt; and the documentation is basically a copy of the signature with some descriptive text. But the text says nothing of how to actually &lt;em&gt;use&lt;/em&gt; the function. I just want to know how I use the pointer. A descriptive example is gold worth as it saves you so much time:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;ptr&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; v &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;1i&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; p &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; v.&lt;span class=&quot;support function rust&quot;&gt;as_mut_ptr&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;unsafe&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta path rust&quot;&gt;ptr&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;write&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; 9i&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta path rust&quot;&gt;ptr&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;write&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;p.&lt;span class=&quot;support function rust&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; 5i&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support macro rust&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;v&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;9i&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You don’t even have to be that familiar with rust to see what the function does and how to use it with little more than a glance.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2014/07/19/my_first_rust_contribution/&quot; title=&quot;My first rust contribution&quot;&gt;My first rust contribution&lt;/a&gt; was a main example for &lt;a href=&quot;http://doc.rust-lang.org/std/collections/struct.HashSet.html&quot; title=&quot;std::collections::HashSet&quot;&gt;HashSet&lt;/a&gt; and my &lt;a href=&quot;https://github.com/rust-lang/rust/pull/17339&quot; title=&quot;doc: Method examples for Result and Option #17339&quot;&gt;last accepted pull request&lt;/a&gt; documented &lt;a href=&quot;http://doc.rust-lang.org/std/result/enum.Result.html&quot; title=&quot;std::result::Result&quot;&gt;Result&lt;/a&gt; and &lt;a href=&quot;http://doc.rust-lang.org/std/option/enum.Option.html&quot; title=&quot;std::option::Option&quot;&gt;Option&lt;/a&gt; which is quite fitting as most of my contributions were documentation related. When finished I had made sure &lt;a href=&quot;http://doc.rust-lang.org/collections/index.html&quot; title=&quot;rust std::collections&quot;&gt;collections&lt;/a&gt; had runnable examples for everything except deprecated items and some which should be reworked (like btree). I made larger examples for &lt;a href=&quot;http://doc.rust-lang.org/std/collections/priority_queue/index.html&quot; title=&quot;std::collections::priority_queue&quot;&gt;priority_queue&lt;/a&gt; and &lt;a href=&quot;http://doc.rust-lang.org/std/rand/index.html&quot; title=&quot;std::rand&quot;&gt;rand&lt;/a&gt; using &lt;a href=&quot;/blog/2014/07/23/dijkstras_algorithm/&quot; title=&quot;Dijkstra&amp;#39;s Algorithm&quot;&gt;Dijkstra’s algorithm&lt;/a&gt; and a &lt;a href=&quot;/blog/2014/07/30/monty_hall/&quot; title=&quot;Monty Hall simulation&quot;&gt;Monty Hall simulation&lt;/a&gt; which turned out quite decent and some documentation for other things.&lt;/p&gt;
&lt;p&gt;Writing examples was more fun than I had initially thought and the reviewers seemed very happy with my contributions, which feels good. I might do something more in the future.&lt;/p&gt;
&lt;h1&gt;Issues&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; uses &lt;a href=&quot;https://github.com/rust-lang/rust/issues&quot; title=&quot;rust issues&quot;&gt;issues&lt;/a&gt; for everything from bugs to smaller feature requests. I fixed some easier ones like &lt;a href=&quot;https://github.com/rust-lang/rust/issues/16877&quot; title=&quot;failure with non-UTF8 formatting leads to hard-to-debug error #16877&quot;&gt;preventing failure with non-UTF8 formatting&lt;/a&gt; and &lt;a href=&quot;https://github.com/rust-lang/rust/issues/16945&quot; title=&quot;JSON decoding fails on trailing comma #16945&quot;&gt;JSON decoding fails on trailing comma&lt;/a&gt;. Even though the issues and the fixes are small, a lot of time went into fixing them. Time searching for issues and time spent familiarizing with the code base easily trumps time actually writing the resulting code.&lt;/p&gt;
&lt;p&gt;For example when I tried to fix &lt;a href=&quot;https://github.com/rust-lang/rust/issues/12794&quot; title=&quot;Modify Json Decoder to handle missing/optional Json fields if mapped to Option #12794&quot;&gt;#12794&lt;/a&gt;, to modify json decoder to handle optional fields, a lot of time was spent reading about &lt;code&gt;#[deriving(Decodable)]&lt;/code&gt; and how it’s implemented and I hoped to introduce a general way for all types deriving &lt;code&gt;Decodable&lt;/code&gt; to handle optional types. This led me to investigate syntax extension and fairly deep compiler hooks, but this led me to a bit of a dead end and the final pull request is a simpler hard-coded &lt;code&gt;Option&lt;/code&gt; handling for json.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/pulls?q=author%3Atreeman+&quot; title=&quot;rust author:treeman&quot;&gt;My issues and pull requests&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Bug triage&lt;/h1&gt;
&lt;p&gt;Another way to contribute is to enter rust’s &lt;a href=&quot;http://www.reddit.com/r/rust/comments/1w10ip/bug_triage_program/&quot; title=&quot;rust bug triage program&quot;&gt;bug triage program&lt;/a&gt; where you receive a random set of old issues (I got 10 each week) and your task is to solve, bump, close or clarify them to the best of your ability.&lt;/p&gt;
&lt;p&gt;I don’t think I actually managed solve a lot of issues, maybe a couple, but I did try to. At the very least I tried to replicate old issues to see if they’re still relevant and if so make an up to date test case. If not I’d usually just bump the issue.&lt;/p&gt;
&lt;h1&gt;RFC&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; uses the &lt;a href=&quot;https://github.com/rust-lang/rfcs&quot; title=&quot;rust RFCs&quot;&gt;RFC&lt;/a&gt; process which all “substantial” changes to the language have to go through. Changing semantics, adding keywords or changes to the standard library are typical examples which requires an RFC.&lt;/p&gt;
&lt;p&gt;Early on when reading rust’s old tutorial I cringed a bit of the use of Newtypes:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;Inch&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;int&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; length &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; Inch&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; Inch&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;integer_length&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; length&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;it&amp;#39;s &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; long!&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; integer_length&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But this isn’t very ergonomic and it just feels like a big hack to call a one element tuple for a newtype. So I wrote an &lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/186&quot; title=&quot;Introduce a newtype keyword. #186&quot;&gt;RFC&lt;/a&gt; which proposed to introduce a &lt;code&gt;newtype&lt;/code&gt; keyword which automatically derives the underlying traits of a type:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;newtype Inch &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; int&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; length&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; Inch &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;it&amp;#39;s &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; long!&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; length&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The feedback was positive overall, but it’s currently postponed until after 1.0 as it could be implemented with backwards compatibility in mind. There was also discussion about possibly favouring &lt;a href=&quot;https://www.haskell.org/ghc/docs/7.8.1/html/users_guide/deriving.html#newtype-deriving&quot; title=&quot;Generalized Newtype Deriving&quot;&gt;Generalized Newtype Deriving&lt;/a&gt; over a new keyword:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;deriving&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;Sub&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Show&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;Inches&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;int&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which gives the ability to skip unwanted traits, for example multiplication might not make sense for an &lt;code&gt;Inch&lt;/code&gt; as the resulting type would be &lt;code&gt;Inch^2&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;What it meant to me&lt;/h1&gt;
&lt;p&gt;I had a blast doing summer of code! It has long been a wish of mine to contribute to open source and rust has fascinated me a long time and I’m really happy I got the chance to work &lt;em&gt;and to get paid&lt;/em&gt; doing this. Having a summer job doing something you might do anyway is per definition a great summer job.&lt;/p&gt;
&lt;p&gt;It was more than just getting paid, it also gave me a push to becoming a contributor to &lt;a href=&quot;http://rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; which is big confidence boost for me and hopefully it gives me a good starting point to contribute more in the future. And of course it gave me a nice excuse to play with &lt;a href=&quot;http://rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt;, which is really shaping up to be a nice language.&lt;/p&gt;
</content></entry><entry><title>ISOC update</title><id>http://jonashietala.se/blog/2014/09/04/isoc_update/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/09/04/isoc_update" rel="alternate"/><published>2014-09-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I have now worked a bit more than 3 weeks out of my 4 weeks of &lt;a href=&quot;/blog/2014/06/11/isoc/&quot; title=&quot;IDA Summer of Code&quot;&gt;IDA Summer of Code&lt;/a&gt; and this is an update post of what I’ve done so far. I will write a more extensive summary post at the end of the project. I was planning on writing a weekly summary, but that ship sailed a long time ago.&lt;/p&gt;
&lt;p&gt;I’ve written a lot of documenting code examples, specifically making sure most of the methods in &lt;a href=&quot;http://doc.rust-lang.org/collections/index.html&quot; title=&quot;rust collection doc&quot;&gt;collections&lt;/a&gt; had examples. I’m especially proud of the main examples for &lt;a href=&quot;http://doc.rust-lang.org/std/collections/priority_queue/index.html&quot; title=&quot;rust priority_queue doc&quot;&gt;priority_queue&lt;/a&gt; and &lt;a href=&quot;http://doc.rust-lang.org/std/rand/index.html&quot; title=&quot;rust rand doc&quot;&gt;rand&lt;/a&gt; I wrote about &lt;a href=&quot;/blog/2014/07/23/dijkstras_algorithm/&quot; title=&quot;Dijkstra&amp;#39;s algorithm&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;/blog/2014/07/30/monty_hall/&quot; title=&quot;Monty Hall&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have one &lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/186&quot; title=&quot;Introduce a newtype keyword&quot;&gt;RFC&lt;/a&gt; where I propose to introduce a new keyword &lt;code&gt;newtype&lt;/code&gt;. I don’t think it will be accepted, but it spurred some good discussions and &lt;em&gt;something&lt;/em&gt; similar might be included further down the road. It remains to be seen if it will be with a new keyword or if we’ll utilize existing constructions.&lt;/p&gt;
&lt;p&gt;Other than that I’ve done a bit of triage: the act of looking up old issues to see if they are relevant, update them and preferably fix them. I have done some small fixes to a couple of issues, most have been very minor ones like adjusting error messages or adding tests.&lt;/p&gt;
&lt;p&gt;The time I have left I will try to fix more issues. This week I tried to add &lt;a href=&quot;https://github.com/rust-lang/rust/issues/12794&quot; title=&quot;rust issue #12794&quot;&gt;default arguments for json decoding when using &lt;code&gt;Option&lt;/code&gt;&lt;/a&gt;, but I approached it the wrong way. I may attempt to do it “the right way” but I’m unsure if I can come up with a nice way.&lt;/p&gt;
</content></entry><entry><title>Embedding youtube videos with Hakyll</title><id>http://jonashietala.se/blog/2014/09/01/embedding_youtube_videos_with_hakyll/index.html</id><updated>2026-04-27T11:09:41+00:00</updated><link href="https://www.jonashietala.se/blog/2014/09/01/embedding_youtube_videos_with_hakyll" rel="alternate"/><published>2014-09-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A while ago a made a timelapse of my entry to Ludum Dare. This is how I parse and embed videos using &lt;a href=&quot;http://jaspervdj.be/hakyll/&quot; title=&quot;Hakyll&quot;&gt;Hakyll&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I don’t want to remember any special syntax for embedding, I don’t want to bother (remember?) to use something like &lt;code&gt;{% youtube: &amp;lt;link&amp;gt; %}&lt;/code&gt; or whatever syntax we might find pretty. The simplest solution I could think of is simply to have a bare link separated by newlines:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Some text...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;link&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Some other text...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Would embed &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; as a video. A youtube link seems to always start like: &lt;code&gt;https://www.youtube.com/watch?v=&lt;/code&gt; which we can parse with a simple regex. If we run this after compilation the link will also be surrounded by &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash haskell&quot;&gt;&lt;span class=&quot;punctuation definition comment haskell&quot;&gt;--&lt;/span&gt; Need to import the regex
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta import haskell&quot;&gt;&lt;span class=&quot;keyword other haskell&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;support other module haskell&quot;&gt;Text.Regex&lt;/span&gt; &lt;span class=&quot;meta declaration exports haskell&quot;&gt;(&lt;span class=&quot;entity name function haskell&quot;&gt;subRegex&lt;/span&gt;&lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;entity name function haskell&quot;&gt;mkRegex&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-dash haskell&quot;&gt;&lt;span class=&quot;punctuation definition comment haskell&quot;&gt;--&lt;/span&gt; Find and replace bare youtube links separated by &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;youtubeFilter&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;youtubeFilter x &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;subRegex regex x result
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword other haskell&quot;&gt;where&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    regex &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; mkRegex &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;p&amp;gt;https?://www&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;.youtube&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;.com/watch&lt;span class=&quot;constant character escape haskell&quot;&gt;\\&lt;/span&gt;?v=([A-Za-z0-9_-]+)&amp;lt;/p&amp;gt;&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    result &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;&amp;lt;div class=&lt;span class=&quot;constant character escape haskell&quot;&gt;\&amp;quot;&lt;/span&gt;video-wrapper&lt;span class=&quot;constant character escape haskell&quot;&gt;\&amp;quot;&lt;/span&gt;&amp;gt;\&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;keyword operator haskell&quot;&gt;\&amp;lt;&lt;/span&gt;div &lt;span class=&quot;meta declaration class haskell&quot;&gt;&lt;span class=&quot;keyword other haskell&quot;&gt;class&lt;/span&gt;=\&amp;quot;&lt;span class=&quot;variable other generic-type haskell&quot;&gt;video&lt;/span&gt;-&lt;span class=&quot;variable other generic-type haskell&quot;&gt;container&lt;/span&gt;\&amp;quot;&amp;gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                  \&amp;lt;&lt;span class=&quot;variable other generic-type haskell&quot;&gt;iframe&lt;/span&gt; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;src&lt;/span&gt;=\&amp;quot;//&lt;span class=&quot;variable other generic-type haskell&quot;&gt;www&lt;/span&gt;.&lt;span class=&quot;variable other generic-type haskell&quot;&gt;youtube&lt;/span&gt;.&lt;span class=&quot;variable other generic-type haskell&quot;&gt;com&lt;/span&gt;/&lt;span class=&quot;variable other generic-type haskell&quot;&gt;embed&lt;/span&gt;/\\1\&amp;quot; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;frameborder&lt;/span&gt;=\&amp;quot;0\&amp;quot; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;allowfullscreen&lt;/span&gt;/&amp;gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                \&amp;lt;/&lt;span class=&quot;variable other generic-type haskell&quot;&gt;div&lt;/span&gt;&amp;gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             \&amp;lt;/&lt;span class=&quot;variable other generic-type haskell&quot;&gt;div&lt;/span&gt;&amp;gt;&amp;quot;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; The solution above does not handle unicode in the document before the video. See an update &lt;a href=&quot;/blog/2019/01/25/regex_substitution_with_unicode_in_haskell/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The rendering part is not pretty and I’m sure one could move it to a template somehow.&lt;/p&gt;
&lt;p&gt;We can use with:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function type-declaration haskell&quot;&gt;&lt;span class=&quot;entity name function haskell&quot;&gt;applyFilter&lt;/span&gt; &lt;span class=&quot;keyword other double-colon haskell&quot;&gt;::&lt;/span&gt; (&lt;span class=&quot;storage type haskell&quot;&gt;Monad&lt;/span&gt; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;m&lt;/span&gt;, &lt;span class=&quot;storage type haskell&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;f&lt;/span&gt;) &lt;span class=&quot;keyword other big-arrow haskell&quot;&gt;=&amp;gt;&lt;/span&gt; (&lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt;) &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;keyword other arrow haskell&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;variable other generic-type haskell&quot;&gt;m&lt;/span&gt; (&lt;span class=&quot;variable other generic-type haskell&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;storage type haskell&quot;&gt;String&lt;/span&gt;)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;applyFilter transformator str &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;/span&gt;return &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; (fmap &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; transformator) str
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And use it right after we compile:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;match &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;posts/*.markdown&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    route   postRoute
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    compile &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; pandocCompiler
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; applyFilter youtubeFilter
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; saveSnapshot &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;content&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; return &lt;span class=&quot;keyword operator haskell&quot;&gt;.&lt;/span&gt; fmap demoteHeaders
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; saveSnapshot &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;demoted_content&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; loadAndApplyTemplate &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;templates/post.html&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; (postCtx tags)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; saveSnapshot &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;post&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; loadAndApplyTemplate &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;templates/site.html&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; (postCtx tags)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; deIndexUrls
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I did not write this code originally, I found it on someone else’s blog, but I managed to loose the link and now I can’t find it.&lt;/p&gt;
&lt;p&gt;The styling of the video is &lt;a href=&quot;http://webdesignerwall.com/tutorials/css-elastic-videos&quot; title=&quot;CSS elastic videos&quot;&gt;from another blog post&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;css&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight css&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;video-container&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;relative&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding-bottom&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;56.25&lt;span class=&quot;keyword other unit css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;padding-top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;30&lt;span class=&quot;keyword other unit css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;height&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;overflow&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;hidden&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;video-container&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;iframe&lt;/span&gt;, &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;video-container&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;object&lt;/span&gt;, &lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;video-container&lt;/span&gt; &lt;span class=&quot;entity name tag css&quot;&gt;embed&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;position&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;support constant property-value css&quot;&gt;absolute&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;top&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;left&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;100&lt;span class=&quot;keyword other unit css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;height&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;100&lt;span class=&quot;keyword other unit css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta selector css&quot;&gt;&lt;span class=&quot;entity other attribute-name class css&quot;&gt;&lt;span class=&quot;punctuation definition entity css&quot;&gt;.&lt;/span&gt;video-wrapper&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta property-list css&quot;&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;600&lt;span class=&quot;keyword other unit css&quot;&gt;px&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta property-name css&quot;&gt;&lt;span class=&quot;support type property-name css&quot;&gt;max-width&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value css&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta property-value css&quot;&gt;&lt;span class=&quot;constant numeric css&quot;&gt;100&lt;span class=&quot;keyword other unit css&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rule css&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section property-list css&quot;&gt;}&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now in the end this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;https://www.youtube.com/watch?v=NIbr-mLi4DU
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Will be transformed to:&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=NIbr-mLi4DU&quot;&gt;https://www.youtube.com/watch?v=NIbr-mLi4DU&lt;/a&gt;
&lt;p&gt;The full source can be found &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot; title=&quot;My Codeberg&quot;&gt;on Codeberg&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><title>Undo git reset --hard</title><id>http://jonashietala.se/blog/2014/08/29/undo_git_reset_--hard/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/08/29/undo_git_reset_--hard" rel="alternate"/><published>2014-08-29T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I purposefully and more or less idiotically executed &lt;code&gt;git reset --hard &amp;lt;hash&amp;gt;&lt;/code&gt; in hopes of going back a bit. What I didn’t realize then is that you throw away all the commits between now until &lt;code&gt;&amp;lt;hash&amp;gt;&lt;/code&gt;. Not quite what was planned.&lt;/p&gt;
&lt;p&gt;After a bit of panic I found &lt;a href=&quot;http://stackoverflow.com/questions/7374069/undo-git-reset-hard/18472148#18472148&quot;&gt;the answer&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find your hash using &lt;code&gt;git reflog&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Do &lt;code&gt;git cherry-pick &amp;lt;hash&amp;gt;&lt;/code&gt; to go back in time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This saved me a bunch of time, thanks!&lt;/p&gt;
</content></entry><entry><title>Vacation</title><id>http://jonashietala.se/blog/2014/08/14/vacation/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/08/14/vacation" rel="alternate"/><published>2014-08-14T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Finally back from a 2 week vacation up at Övertorneå. It’s been pretty great to be taken care of and not doing anything. Well, I did get my ass kicked in Terra Mystica and I played a bit of Minecraft, but still. We got some nice food and my in-laws and my parents were nice.&lt;/p&gt;
&lt;p&gt;I’m still feeling extremely tired though and I don’t know why. The vacation was great but it feels like I need more.  It’s quite horrifying when you come home from your vacation feeling tired.  It’s a sure sign of stress and overexertion but I’m not entirely sure what to do about it.&lt;/p&gt;
&lt;p&gt;I do have a wonderfully supportive girlfriend though, so things aren’t looking all too bleak, maybe I can survive.&lt;/p&gt;
</content></entry><entry><title>Monty Hall</title><id>http://jonashietala.se/blog/2014/07/30/monty_hall/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/07/30/monty_hall" rel="alternate"/><published>2014-07-30T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’m currently reading &lt;a href=&quot;http://www.amazon.com/The-Drunkards-Walk-Randomness-Rules/dp/0307275175&quot; title=&quot;The Drunkard&amp;#39;s Walk&quot;&gt;The Drunkard’s Walk&lt;/a&gt;, a well written book about probabilities.
There they discussed the famous &lt;a href=&quot;http://en.wikipedia.org/wiki/Monty_Hall_problem&quot; title=&quot;The Monty Hall Problem&quot;&gt;Monty Hall Problem&lt;/a&gt;. I’ve heard about it before
and I know the answer, but he mentioned a simulation of the problem and that sounded
cool so I made a simulation of my own. This example will be in the &lt;a href=&quot;http://www.rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; documentation
as well.&lt;/p&gt;
&lt;p&gt;Here’s a quick summary of the problem:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Suppose you’re on a game show, and you’re given the choice of three doors:
Behind one door is a car; behind the others, goats. You pick a door, say No. 1,
and the host, who knows what’s behind the doors, opens another door, say No. 3,
which has a goat. He then says to you, “Do you want to pick door No. 2?”
Is it to your advantage to switch your choice?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The rather unintuitive answer is that you will have a 2/3 chance of winning if
you switch and a 1/3 chance of winning of you don’t, so it’s better to switch.&lt;/p&gt;
&lt;p&gt;This program will simulate the game show and with large enough simulation steps
it will indeed confirm that it is better to switch.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;rand&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;rand&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Rng&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;rand&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;distributions&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;IndependentSample&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; Range&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;SimulationResult&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;win&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;bool&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;bool&lt;/span&gt;,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Run a single simulation of the Monty Hall problem.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;simulate&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;R&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; Rng&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;random_door&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;Range&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;uint&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;variable parameter rust&quot;&gt;rng&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; R&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; SimulationResult&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; car &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; random_door.&lt;span class=&quot;support function rust&quot;&gt;ind_sample&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;rng&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; This is our initial choice
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; choice &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; random_door.&lt;span class=&quot;support function rust&quot;&gt;ind_sample&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;rng&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; The game host opens a door
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; open &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;game_host_open&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;car&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; choice&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; rng&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Shall we switch?
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; switch &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; rng.&lt;span class=&quot;support function rust&quot;&gt;gen&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; switch &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        choice &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;switch_door&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;choice&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; open&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    SimulationResult &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; win&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; choice &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; car&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; switch&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; switch &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Returns the door the game host opens given our choice and knowledge of
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; where the car is. The game host will never open the door with the car.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;game_host_open&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;R&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; Rng&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;car&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint, &lt;span class=&quot;variable parameter rust&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint, &lt;span class=&quot;variable parameter rust&quot;&gt;rng&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; R&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; uint&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; choices &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;free_doors&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;car&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; choice&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta path rust&quot;&gt;rand&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;sample&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;rng&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; choices.&lt;span class=&quot;support function rust&quot;&gt;move_iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Returns the door we switch to, given our current choice and
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; the open door. There will only be one valid door.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;switch_door&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint, &lt;span class=&quot;variable parameter rust&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; uint&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support function rust&quot;&gt;free_doors&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;choice&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; open&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;free_doors&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;blocked&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;[uint]&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Vec&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;uint&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;!&lt;/span&gt;blocked.&lt;span class=&quot;support function rust&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;x&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; The estimation will be more accurate with more simulations
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; num_simulations &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; 10000u&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; rng &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;rand&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;task_rng&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; random_door &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;Range&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; switch_wins&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; switch_losses&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; 0u&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; keep_wins&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; keep_losses&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; 0u&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;Running &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; simulations...&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; num_simulations&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; num_simulations&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; result &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;simulate&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;random_door&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; rng&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;result.win&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; result.switch&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant language rust&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language rust&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; switch_wins &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant language rust&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language rust&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; keep_wins &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant language rust&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language rust&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; switch_losses &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant language rust&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant language rust&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; keep_losses &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; total_switches &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; switch_wins &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; switch_losses&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; total_keeps &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; keep_wins &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; keep_losses&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;Switched door &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; times with &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; wins and &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; losses&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    total_switches&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; switch_wins&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; switch_losses&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;Kept our choice &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; times with &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; wins and &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; losses&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    total_keeps&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; keep_wins&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; keep_losses&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; With a large number of simulations, the values should converge to
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; 0.667 and 0.333 respectively.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;Estimated chance to win if we switch: &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    switch_wins &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;f32&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;/&lt;/span&gt; total_switches &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;f32&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;Estimated chance to win if we don&amp;#39;t: &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    keep_wins &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;f32&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;/&lt;/span&gt; total_keeps &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;f32&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is an example run:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;$ ./monty_hall
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Running 10000 simulations...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Switched door 4994 times with 3323 wins and 1671 losses
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Kept our choice 5006 times with 1619 wins and 3387 losses
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Estimated chance to win if we switch: 0.665399
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Estimated chance to win if we don&apos;t: 0.323412
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>Dijkstra&apos;s Algorithm</title><id>http://jonashietala.se/blog/2014/07/23/dijkstras_algorithm/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/07/23/dijkstras_algorithm" rel="alternate"/><published>2014-07-23T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;For &lt;a href=&quot;http://rust-lang.org/&quot;&gt;rust&lt;/a&gt;, I’m updating the documentation for the standard library and specifically with the collections. For the priority queue I had the idea to use &lt;a href=&quot;http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm&quot; title=&quot;Dijkstra&amp;#39;s algorithm&quot;&gt;Dijkstra’s algorithm&lt;/a&gt; as a fun example. That idea was &lt;a href=&quot;https://github.com/rust-lang/rust/pull/15857&quot; title=&quot;#15857&quot;&gt;well received&lt;/a&gt; and that example is now &lt;a href=&quot;http://doc.rust-lang.org/std/collections/priority_queue/index.html&quot; title=&quot;rust priority_queue doc&quot;&gt;live&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At first I wanted to use &lt;a href=&quot;http://en.wikipedia.org/wiki/A*_search_algorithm&quot; title=&quot;A* search algorithm&quot;&gt;A*&lt;/a&gt; to solve &lt;a href=&quot;http://en.wikipedia.org/wiki/15_puzzle&quot;&gt;the eight puzzle&lt;/a&gt;, which &lt;a href=&quot;/blog/2014/01/21/8-puzzle_in_rust/&quot; title=&quot;rust code for 8-puzzle&quot;&gt;I’ve done before&lt;/a&gt;, but that example became far too big.&lt;/p&gt;
&lt;p&gt;Here’s the example code currently up in &lt;a href=&quot;http://doc.rust-lang.org/std/collections/priority_queue/index.html&quot; title=&quot;rust priority_queue doc&quot;&gt;docs&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;rustc 0.12.0-pre (ef352faea84fa16616b773bd9aa5020d7c76bff0 2014-07-18 21:46:32 +0000&lt;/code&gt;)&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;collections&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;PriorityQueue&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;uint&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;deriving&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;Eq&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; PartialEq&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; The priority queue depends on `Ord`.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Explicitly implement the trait so the queue becomes a min-heap
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; instead of a max-heap.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;storage type impl rust&quot;&gt;impl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;Ord &lt;span class=&quot;keyword other rust&quot;&gt;for&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt; &lt;span class=&quot;entity name impl rust&quot;&gt;State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;cmp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;, &lt;span class=&quot;variable parameter rust&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;State&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; Ordering&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Notice that the we flip the ordering here
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        other.cost.&lt;span class=&quot;support function rust&quot;&gt;cmp&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.cost&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; `PartialOrd` needs to be implemented as well.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;storage type impl rust&quot;&gt;impl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;PartialOrd &lt;span class=&quot;keyword other rust&quot;&gt;for&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt; &lt;span class=&quot;entity name impl rust&quot;&gt;State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;partial_cmp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;, &lt;span class=&quot;variable parameter rust&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;State&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Option&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;Ordering&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support type rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;cmp&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;other&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Each node is represented as an `uint`, for a shorter implementation.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;Edge&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Dijkstra&amp;#39;s shortest path algorithm.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Start at `start` and use `dist` to track the current shortest distance
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; to each node. This implementation isn&amp;#39;t memory efficient as it may leave duplicate
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; nodes in the queue. It also uses `uint::MAX` as a sentinel value,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; for a simpler implementation.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;shortest_path&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;adj_list&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;Vec&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;meta generic rust&quot;&gt;Vec&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;Edge&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition generic end rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;variable parameter rust&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint, &lt;span class=&quot;variable parameter rust&quot;&gt;goal&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; uint&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; dist[node] = current shortest distance from `start` to `node`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; dist &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support type rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;from_elem&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;adj_list.&lt;span class=&quot;support function rust&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;uint&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant other rust&quot;&gt;MAX&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; pq &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;PriorityQueue&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; We&amp;#39;re at `start`, with a zero cost
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;dist.&lt;span class=&quot;support function rust&quot;&gt;get_mut&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;start&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; 0u&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    pq.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;State &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; 0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; position&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; start &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Examine the frontier with lower cost nodes first (min-heap)
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; State &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; position &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;match&lt;/span&gt; pq.&lt;span class=&quot;support function rust&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support type rust&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; empty
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;support type rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; s
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Alternatively we could have continued to find all shortest paths
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; position &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; goal &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;return&lt;/span&gt; cost &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Important as we may have already found a better way
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; cost &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt; dist&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;position&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;continue&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; For each node we can reach, see if we can find a way with
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; a lower cost going through this node
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; edge &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; adj_list&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;position&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; next &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; State &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; cost &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; edge.cost&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; position&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; edge.node &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; If so, add it to the frontier and continue
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; next.cost &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;lt;&lt;/span&gt; dist&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;next.position&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                pq.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Relaxation, we have now found a better way
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;                &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;dist.&lt;span class=&quot;support function rust&quot;&gt;get_mut&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next.position&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; next.cost&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Goal not reachable
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta path rust&quot;&gt;uint&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant other rust&quot;&gt;MAX&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; This is the directed graph we&amp;#39;re going to use.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; The node numbers correspond to the different states,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; and the edge weights symbolises the cost of moving
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; from one node to another.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Note that the edges are one-way.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;                  7
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          +-----------------+
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          |                 |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          v   1        2    |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          0 -----&amp;gt; 1 -----&amp;gt; 3 ---&amp;gt; 4
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          |        ^        ^      ^
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          |        | 1      |      |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          |        |        | 3    | 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;          +------&amp;gt; 2 -------+      |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;           10      |               |
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;                   +---------------+
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; The graph is represented as an adjecency list where each index,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; corresponding to a node value, has a list of outgoing edges.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Chosen for it&amp;#39;s efficiency.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; graph &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Node 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;10&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Node 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Node 2
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Node 3
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;7&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;             Edge &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; node&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Node 4
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;support macro rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function rust&quot;&gt;shortest_path&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;graph&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function rust&quot;&gt;shortest_path&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;graph&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function rust&quot;&gt;shortest_path&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;graph&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function rust&quot;&gt;shortest_path&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;graph&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;assert_eq!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function rust&quot;&gt;shortest_path&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;graph&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;uint&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant other rust&quot;&gt;MAX&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>My first rust Contribution</title><id>http://jonashietala.se/blog/2014/07/19/my_first_rust_contribution/index.html</id><updated>2024-01-17T12:41:05+00:00</updated><link href="https://www.jonashietala.se/blog/2014/07/19/my_first_rust_contribution" rel="alternate"/><published>2014-07-19T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The problem with open-source for most people isn’t writing code, but it’s all the other things.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;How shall I push my changes? How do I handle &lt;a href=&quot;http://git-scm.com/&quot; title=&quot;git&quot;&gt;git&lt;/a&gt;? What should I do?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was the same and I actually dreaded &lt;a href=&quot;/blog/2014/06/11/isoc/&quot; title=&quot;IDA Summer of Code&quot;&gt;my awesome summer job&lt;/a&gt;, just a little bit, because now I’m supposed to contribute and preferrably a non-trivial amount. Although I’ve been programming several years, I’ve never contributed a large open-source project. Or a small one for that matter.&lt;/p&gt;
&lt;p&gt;But this has now officially changed. 3 days ago &lt;a href=&quot;https://github.com/rust-lang/rust/pull/15667&quot; title=&quot;issue #15667&quot;&gt;my first pull request&lt;/a&gt; got merged into &lt;a href=&quot;http://www.rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt;! Here are some useful steps and resources which might be useful for someone in my shoes:&lt;/p&gt;
&lt;p&gt;I assume you’re going to contribute to &lt;a href=&quot;http://www.rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt;, but the essence could be generalized for other projects as well.&lt;/p&gt;
&lt;h1&gt;Build&lt;/h1&gt;
&lt;p&gt;Firstly we should try to &lt;a href=&quot;https://github.com/rust-lang/rust/wiki/Note-getting-started-developing-Rust&quot; title=&quot;Build rust&quot;&gt;build rust&lt;/a&gt;. There are some useful things about building inside the root &lt;code&gt;Makefile&lt;/code&gt; and in the &lt;a href=&quot;https://github.com/rust-lang/rust/wiki/Note-testsuite&quot; title=&quot;Test suite&quot;&gt;test suite notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For making the documentation:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; docs NO_REBUILD=1&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And making other things:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;j&lt;/span&gt;&lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;lt;&lt;/span&gt;num-cores&lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;gt;&lt;/span&gt; NO_REBUILD=1 NO_BENCH=1 CFG_DISABLE_VALGRIND=1&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The process can be very slow though, especially if you do &lt;code&gt;make clean&lt;/code&gt; (try not to!).&lt;/p&gt;
&lt;h1&gt;Git workflow&lt;/h1&gt;
&lt;p&gt;Before we start hacking it’s good to have an idea of the git workflow we’re going to use.&lt;/p&gt;
&lt;p&gt;Firstly, clone &lt;code&gt;git@github.com:rust-lang/rust.git&lt;/code&gt; and push that repo into your github account. I have that as my &lt;code&gt;origin&lt;/code&gt;. Then create an &lt;code&gt;upstream&lt;/code&gt; branch:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;git&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; remote add upstream https://github.com/rust-lang/rust&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For me it looks like this:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; git remote&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;v&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;origin&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;      git@github.com:treeman/rust.git (fetch&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta post-cmd shell&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;origin&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;      git@github.com:treeman/rust.git (push&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta post-cmd shell&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;upstream&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;    https://github.com/rust-lang/rust (fetch&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta post-cmd shell&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;upstream&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;    https://github.com/rust-lang/rust (push&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta post-cmd shell&quot;&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we want to start working on something new, always create a new branch:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; git checkout master&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;b&lt;/span&gt; mybranch&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While we’re working we need to update from &lt;code&gt;upstream&lt;/code&gt;, to get new changes.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; git checkout mybranch&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; git fetch upstream&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; git rebase upstream/master&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When done, push locally to github:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; git push origin mybranch&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To file a pull request we can use github’s interface. Just be sure to target the &lt;code&gt;master&lt;/code&gt; integration branch.&lt;/p&gt;
&lt;p&gt;If we want to make some changes to our pull request, simply make the changes in &lt;code&gt;mybranch&lt;/code&gt; and push towards your github profile.&lt;/p&gt;
&lt;p&gt;If you have a lot of commits in your pull request, or if they aren’t very descriptive, you may be asked to squash your commits. Sounds scary, but it’s fairly straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git log&lt;/code&gt; and check how many commits you have (or check via github).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git rebase -i HEAD~2&lt;/code&gt; will rebase the 2 latest commits.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When satisfied:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;shell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight shell&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; git push origin mybranch&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;f&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s it! Make sure to switch branch when you’re done. I accidentally pushed another commit on top of my already reviewed, and accepted, pull request. Quite embarrassing but I’ll live =)&lt;/p&gt;
&lt;h1&gt;Actual work&lt;/h1&gt;
&lt;p&gt;With that taken care of, we can finally do some work. But &lt;a href=&quot;https://github.com/rust-lang/rust/wiki/Note-guide-for-new-contributors&quot; title=&quot;Note guide for new contributors&quot;&gt;what to do&lt;/a&gt;? Here are some tips:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Document the &lt;a href=&quot;http://doc.rust-lang.org/std/&quot; title=&quot;rust std library&quot;&gt;library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At the time of my writing, the library lacks a lot of documentation, and that’s what I’m doing. And don’t be scared, it’s not as dry as it’s sounds. My contributions are basically just adding code examples.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write unit tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proofread the &lt;a href=&quot;http://doc.rust-lang.org/tutorial.html&quot; title=&quot;rust tutorial&quot;&gt;tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I did this, but the tutorial is currently getting a complete rewrite, so I’m not sure how useful that was.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find and fix some &lt;a href=&quot;https://github.com/rust-lang/rust/issues?direction=desc&amp;amp;sort=created&amp;amp;state=open&quot; title=&quot;rust Issues&quot;&gt;bugs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;rust organizes everything as issues. Feature request, updates and bugs. If you look for them, you might find an &lt;a href=&quot;https://github.com/rust-lang/rust/issues/15780&quot; title=&quot;issue #15780&quot;&gt;easy bug&lt;/a&gt; to work on. Which is what &lt;a href=&quot;https://github.com/rust-lang/rust/pull/15785&quot; title=&quot;issue #15785&quot;&gt;I did&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And you can always simply start hacking on something interesting. Or find and fix a bug yourself.&lt;/p&gt;
</content></entry><entry><title>Plans for Summer of Code</title><id>http://jonashietala.se/blog/2014/07/14/plans_for_summer_of_code/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/07/14/plans_for_summer_of_code" rel="alternate"/><published>2014-07-14T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;My &lt;a href=&quot;/blog/2014/07/13/summer_job_at_configura&quot; title=&quot;Summer job at Configura&quot;&gt;first summer job&lt;/a&gt; is now over, and after a weekend of rest, it is now time to plan for my second summer job: &lt;a href=&quot;/blog/2014/06/11/isoc&quot; title=&quot;IDA Summer of Code&quot;&gt;IDA Summer of Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will work a month, or 4 weeks, with contributing to &lt;a href=&quot;http://www.rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt;! The only issue is, I have no idea where to start. I didn’t have a strict plan or a vision of what I want to accomplish when I applied, but now I’m running out of time. I need to have an attack plan.&lt;/p&gt;
&lt;p&gt;First thing first is to read through the &lt;a href=&quot;http://doc.rust-lang.org/tutorial.html&quot; title=&quot;rust tutorial&quot;&gt;tutorial&lt;/a&gt; and to review rust a bit. After that I should go through the open &lt;a href=&quot;https://github.com/rust-lang/rust/issues?labels=&amp;amp;page=1&amp;amp;state=open&quot; title=&quot;rust issues&quot;&gt;issues&lt;/a&gt; and perhaps find an easy issue I can start working on. The idea is to perhaps start with documentation and work from there.&lt;/p&gt;
&lt;p&gt;I will also track the irc channel &lt;code&gt;#rust@irc.mozilla.org&lt;/code&gt; and use their &lt;a href=&quot;https://mail.mozilla.org/listinfo/rust-dev&quot; title=&quot;rust mailing list&quot;&gt;mailing list&lt;/a&gt;. I’ve been idling in their irc channel a while now and they are very friendly and helpful, so I’m sure I’ll be able to get help and pointers from them.&lt;/p&gt;
&lt;p&gt;But before all that, I need to clean my desk…&lt;/p&gt;
</content></entry><entry><title>Summer job at Configura</title><id>http://jonashietala.se/blog/2014/07/13/summer_job_at_configura/index.html</id><updated>2024-06-27T07:56:53+00:00</updated><link href="https://www.jonashietala.se/blog/2014/07/13/summer_job_at_configura" rel="alternate"/><published>2014-07-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is a wrap up of my 5 weeks at &lt;a href=&quot;http://www.configura.com/&quot; title=&quot;Configura&quot;&gt;Configura&lt;/a&gt; as a summer internship. There were 6 interns and we had two teams doing different things. I worked with two other awesome guys and it was great!&lt;/p&gt;
&lt;h1&gt;The Premise&lt;/h1&gt;
&lt;p&gt;We had two assignments this summer. One was to create an optimized version of an octree (more on that later). We had a reference implementation in CM, but we wanted to take it down to C++ and to optimize it and make it stable and robust. This was a self-contained assignment which could be used for various things in their application.&lt;/p&gt;
&lt;p&gt;The second assignment was to use our octree and simplify meshes by removing invisible triangles from them. Here again we had a reference implementation to work with but we were going to make it faster and more robust.&lt;/p&gt;
&lt;p&gt;On top of that we had to make debugging and visualization tools and a test suite.&lt;/p&gt;
&lt;h1&gt;The Result&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/configura14/argonath1.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;In this picture we can see the original model on the left. The green outline to the right are the triangles we deemed visible and the red mesh corresponds to the invisible triangles.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/configura14/argonath2.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Here we only show the removed triangles and we can see that there’s a dude inside the statue, which we mostly remove. This model has about 730 000 triangles and we managed to remove about 300 000 of them, which is pretty cool.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/configura14/adolf1.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;This is another interesting example. We can see that inside this model, we have a high resolution spring with nearly 3500 triangles!&lt;/p&gt;
&lt;p&gt;As for speed, we significantly improved the runtime of both the octree and the ray casting. For a specific model with 20 000 triangles which took around 15 minutes with a small depth, we managed to get it down to about a second with a larger depth. We achieved similar results with the ray casting.&lt;/p&gt;
&lt;p&gt;In the end our bosses seemed pleased, so I consider the summer job a success. I did suck at Disc Golf though.&lt;/p&gt;
&lt;h1&gt;Execution&lt;/h1&gt;
&lt;h2&gt;Octree&lt;/h2&gt;
&lt;p&gt;An &lt;a href=&quot;http://en.wikipedia.org/wiki/Octree&quot; title=&quot;Octree&quot;&gt;octree&lt;/a&gt; is an extension of a &lt;a href=&quot;http://en.wikipedia.org/wiki/Quadtree&quot; title=&quot;Quadtree&quot;&gt;quadtree&lt;/a&gt; from 2D to 3D. The simple explanation is that we have a box, and try to insert triangles (or points, or whatever) into it. When the box has enough triangles we split it into 8 parts (4 with a quadtree) and then insert the triangles into the new boxes if they intersect them.&lt;/p&gt;
&lt;p&gt;The octree is used in various ways, for a fast traversal with a ray, mesh healing, finding neighbours or other things.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/configura14/octree1.png&quot;&gt;&lt;img src=&quot;/images/configura14/octree1.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/configura14/octree2.png&quot;&gt;&lt;img src=&quot;/images/configura14/octree2.png&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Here we can see the root bounding box and the subsequent subdivision into smaller boxes. The green boxes have none or few triangles, the yellow and red have more triangles in them. Because we force our wctree to have a maximum depth some nodes like the red ones on top of the model can have a lot of triangles in them without further subdividing. This is basically a trade off between the memory and time usage versus how good the octree becomes.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/configura14/socket1.png&quot;&gt;&lt;img src=&quot;/images/configura14/socket1.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/configura14/socket2.png&quot;&gt;&lt;img src=&quot;/images/configura14/socket2.png&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;This octree is very sparse at the top, which makes sense as there are no triangles there, and it’s dense in the middle. Interestingly we can see something sticking out inside the model, which means there are more triangles there. Indeed, the model has the actual holes, we just can’t see them.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/configura14/octree_debug.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;In this picture we can see one of our debug tools. This is a single large triangle spanning over almost the whole model and the generated octree. The colored boxes show which nodes the triangle is inserted into, which can be an invaluable debugging tool when changing how triangle-box intersection and octree insertion works.&lt;/p&gt;
&lt;p&gt;It also looks cool.&lt;/p&gt;
&lt;p&gt;These are the basic optimization steps we did:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Implement it in C++&lt;/p&gt;
&lt;p&gt;The performance boost you can get by moving down closer to the metal should not be underestimated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use custom memory pools for the triangles, nodes and even the sequences holding them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Implement the AABB triangle intersection tests with the separating axis theorem.&lt;/p&gt;
&lt;p&gt;We had a link to a nice explanation, but now I can’t find it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cache the above triangle projections.&lt;/p&gt;
&lt;p&gt;They will be used &lt;em&gt;a lot&lt;/em&gt;. Use a cache to reuse them when promoting nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don’t start insert from the root and search down, but walk up until we find something we know we’re inside.&lt;/p&gt;
&lt;p&gt;This exploits the fact that the triangles in the meshes are usually “close” to each other. We tried to presort the triangles using a fancy thing called the &lt;a href=&quot;http://en.wikipedia.org/wiki/Hilbert_curve&quot; title=&quot;Hilbert curve&quot;&gt;Hilbert curve&lt;/a&gt; which one can realize using &lt;a href=&quot;http://en.wikipedia.org/wiki/Z-order_curve&quot; title=&quot;Morton Code, Z-order curve&quot;&gt;Morton codes&lt;/a&gt; (using &lt;a href=&quot;http://stackoverflow.com/questions/1024754/how-to-compute-a-3d-morton-number-interleave-the-bits-of-3-intsa&quot; title=&quot;Morton codes, stackoverflow&quot;&gt;fancy bit manipulations&lt;/a&gt;), but unfortunately the presorting pass wasn’t worth it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Ray casting&lt;/h2&gt;
&lt;p&gt;Our strategy for finding invisible triangles is quite simple: we cast rays towards the still invisible triangles from outside the model, and see what we can hit. All triangles our rays hit, are visible and the rest we can remove.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/configura14/casting.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;This is another of our debug tools where we can select a triangle (pointed by the arrow) and all the ray we try to cast towards it. In this case we fail to hit the triangle and instead we hit all the blue/purple triangles instead. This is a failed triangle, but I think it’s a nice illustration of how we tried to find invisible triangles.&lt;/p&gt;
&lt;p&gt;The first pass of rays we only cast one ray along the triangle’s normal towards the visible side of the triangle. During the second pass we start to cast rays in a hemisphere, gradually increasing the density of the rays.&lt;/p&gt;
&lt;p&gt;For each ray we traverse the octree and for every box the ray intersects we check the triangles inside against the ray. This is fast because don’t have to check against all other triangles at every step, but only against a fixed amount if the octree is well formed.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;This was my second summer at &lt;a href=&quot;http://www.configura.com/&quot; title=&quot;Configura&quot;&gt;Configura&lt;/a&gt; and it’s a pretty cool company. They gave us a lot of freedom and we got to work on pretty cool things and they have their own programming language which is fun to work with.&lt;/p&gt;
&lt;p&gt;We rewrote the implementations from scratch, we battled with precision errors and edge cases but in the end our mission was a success. It was a very rewarding experience as the task was quite complex, but we managed to complete it in good style. We got to work with visualization on a high level and we also got to really dive into some low-level optimizations.&lt;/p&gt;
&lt;p&gt;Oh, and something cool we hacked in during my last day: A better triangle flipper to turn triangles face up.&lt;/p&gt;
&lt;figure class=&quot;flex-50&quot;&gt;
&lt;a href=&quot;/images/configura14/flipper1.png&quot;&gt;&lt;img src=&quot;/images/configura14/flipper1.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/configura14/flipper2.png&quot;&gt;&lt;img src=&quot;/images/configura14/flipper2.png&quot; /&gt;&lt;/a&gt;
&lt;figcaption&gt;&lt;p&gt;Left: Triangles turned inwards&lt;br /&gt;
Right: Triangles turned outwards (without blindly copying everything)&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
</content></entry><entry><title>Reinstalling Slackware</title><id>http://jonashietala.se/blog/2014/07/05/reinstalling_slackware/index.html</id><updated>2025-01-19T07:16:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/07/05/reinstalling_slackware" rel="alternate"/><published>2014-07-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I reinstalled slackware on my machine and decided to take some rough notes of the most important steps I made. I did not document the steps in detail, and some are very specific for my setup. But maybe it can be useful for someone, or myself.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Basic-steps&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Basic-steps&quot; class=&quot;heading-ref&quot;&gt;Basic steps&lt;/a&gt;&lt;/h2&gt;
&lt;section id=&quot;Make-slackware-usb-loader&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Make-slackware-usb-loader&quot; class=&quot;heading-ref&quot;&gt;Make slackware usb loader&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;See &lt;code&gt;README_USB.TXT&lt;/code&gt; in usb folder from slackware installation.&lt;/p&gt;
&lt;p&gt;Create&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;dd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; if=usbboot.img of=/dev/sdX bs=1M&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Be sure &lt;code&gt;/dev/sdX&lt;/code&gt; is the usb, dd will wipe everything! Simple way is to 
&lt;code class=&quot;highlight bash&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ls&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; /dev&lt;/span&gt;&lt;/code&gt; before and after plugging in device.  Boot from bios (f2 or f10).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Make-partitions&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Make-partitions&quot; class=&quot;heading-ref&quot;&gt;Make partitions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Make partitions &lt;a href=&quot;http://slackbook.org/html/installation-partitioning.html&quot;&gt;http://slackbook.org/html/installation-partitioning.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fdisk /dev/sda&lt;/code&gt;. Make sure &lt;code&gt;sda&lt;/code&gt; is your harddrive.  Print partitions &lt;code&gt;p&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Current setup:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;tmpfs&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;       4G      swap&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/dev/sda2&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;   50G     /&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/dev/sda3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;   50G     /usr/local&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/dev/sda5&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;   rest    /home&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure that swap is of type Linux Swap, change with &lt;code&gt;t&lt;/code&gt;. Approx 2 times your ram?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Setup&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Setup&quot; class=&quot;heading-ref&quot;&gt;Setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Boot and run &lt;code&gt;setup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Install from FTP/HTTP server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ftp://ftp.slackware.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/pub/slackware/slackware64-14.1/slackware64&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example.&lt;/p&gt;
&lt;p&gt;Don’t pick KDE or Games. Use terse installation.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Config&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Config&quot; class=&quot;heading-ref&quot;&gt;Config&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add a new user with &lt;code&gt;adduser&lt;/code&gt;.  Set zsh as basic shell. Set for root in &lt;code&gt;/etc/passwd&lt;/code&gt; (or update user info there).&lt;/p&gt;
&lt;p&gt;Add user to groups.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;# usermod -a -G netdev username
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Update name in &lt;code&gt;/etc/HOSTNAME&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Install-wicd-get-online&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Install-wicd-get-online&quot; class=&quot;heading-ref&quot;&gt;Install wicd, get online&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Fetch package from &lt;code&gt;/extra/wicd&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;installpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; ...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;chmod&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; +x /etc/rc.d/rc.wicd&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;/etc/rc.d/rc/wicd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; start&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;wicd-curses&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Custom-Kernel&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Custom-Kernel&quot; class=&quot;heading-ref&quot;&gt;Custom Kernel&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://alien.slackbook.org/dokuwiki/doku.php?id=linux:kernelbuilding&quot;&gt;http://alien.slackbook.org/dokuwiki/doku.php?id=linux:kernelbuilding&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fetch latest stable kernel source: &lt;a href=&quot;https://www.kernel.org/&quot;&gt;https://www.kernel.org/&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; /usr/src&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;wget&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.15.1.tar.xz   &lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Or whatever&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;tar&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; xf linux-3.15.1.tar.xz&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rm&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; linux&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; linux-3.15.1 linux&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; linux&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Use slackware custom as base:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; wget or cp to dir&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;wget&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; ftp://ftp.slackware.com/pub/slackware/slackware64-14.1/source/k/config-x86_64/config-generic-3.10.17.x64&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;mv&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; config-generic-3.10.17.x64 .config&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; oldconfig&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; menuconfig&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure to select processor type, preemptive low latency desktop. Remove &lt;code&gt;nvidia&lt;/code&gt; and &lt;code&gt;riba&lt;/code&gt; for nvidia binary blob usage later.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; bzImage modules&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; modules_install&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; arch/x86_64/boot/bzImage /boot/vmlinuz-custom-3.16.3&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; System.map /boot/System.map-custom-3.16.3&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; .config /boot/config-custom-3.16.3&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; /boot&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rm&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; System.map&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; System.map-custom-3.16.3 System.map&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Update &lt;code&gt;/etc/lilo.conf&lt;/code&gt;. This is mine:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Start LILO global section&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;lba32 &lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Allow booting past 1024th cylinder with a recent BIOS&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;compact &lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Fast boot&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Append any additional kernel parameters:&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable other readwrite assignment shell&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;keyword operator assignment shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string unquoted shell&quot;&gt;&lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt; vt.default_utf8=1 logo.nologo&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;boot&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = /dev/sda&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Boot BMP Image.&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Bitmap in BMP format: 640x480x8&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;bitmap&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = /boot/slack.bmp&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Menu colors (foreground, background, shadow, highlighted&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; foreground, highlighted background, highlighted shadow):&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;bmp-colors&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = 255,0,255,0,255,0&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Location of the option table: location x, location y, number of&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; columns, lines per column (max 15), &amp;quot;spill&amp;quot; (this is how many&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; entries must be in the first column before the next begins to&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; be used. We don&amp;#39;t specify it here, as there&amp;#39;s just one column.&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;bmp-table&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = 60,6,1,16&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Timer location x, timer location y, foreground color,&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; background color, shadow color.&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;bmp-timer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = 65,27,0,255&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Standard menu.&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Or, you can comment out the bitmap menu above and&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; use a boot message with the standard menu:&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;message = /boot/boot_message.txt&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Wait until the timeout to boot (if commented out, boot the&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; first entry immediately):&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;prompt&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Timeout before the first entry boots.&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; This is given in tenths of a second, so 600 for every minute:&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;timeout&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = 100&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; Override dangerous defaults that rewrite the partition table:&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;change-rules&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;reset&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;vga&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = 795&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;image&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = /boot/vmlinuz-custom-3.14.5&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;root&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = /dev/sda2&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;label&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = Slack&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;read-only&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;image&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = /boot/vmlinuz&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;root&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = /dev/sda2&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;label&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = Backup&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;read-only&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure to change image locations and drive location.&lt;/p&gt;
&lt;p&gt;Then run &lt;code&gt;lilo&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Fix-X&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Fix-X&quot; class=&quot;heading-ref&quot;&gt;Fix X&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install NVIDIA drivers 337.25.&lt;/p&gt;
&lt;p&gt;Use custom &lt;code&gt;xorg.conf&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; dotfiles/.workspace .&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; /etc/X11/xorg.conf.d/xorg.conf .workspace/xorg.conf&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is it:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;ServerLayout&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Layout0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Screen 0 &quot;Screen0&quot; 1080 480
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Screen 1 &quot;Screen1&quot; 0 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    InputDevice &quot;Keyboard0&quot; &quot;CoreKeyboard&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    InputDevice &quot;Mouse0&quot; &quot;CorePointer&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;Xinerama&quot; &quot;1&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Files&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/misc/:unscaled&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/100dpi/:unscaled&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/75dpi/:unscaled&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/misc/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/Type1/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/Speedo/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/100dpi/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/75dpi/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/cyrillic/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    FontPath &quot;/usr/lib64/X11/fonts/TTF/&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;InputDevice&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Mouse0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Driver &quot;mouse&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;Protocol&quot; &quot;auto&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;Device&quot; &quot;/dev/psaux&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;Emulate3Buttons&quot; &quot;no&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;# Option &quot;ZAxisMapping&quot; &quot;4 5&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;InputDevice&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Keyboard0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Driver &quot;kbd&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;XkbLayout&quot; &quot;us&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;InputClass&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Keyboard Defaults&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    MatchIsKeyboard &quot;yes&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;XkbLayout&quot; &quot;us&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Module&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Load &quot;dbe&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Monitor&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Monitor0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    VendorName &quot;Unknown&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ModelName &quot;DELL U2211H&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    HorizSync 30.0 - 83.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    VertRefresh 56.0 - 76.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;DPMS&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Monitor&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Monitor1&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    VendorName &quot;Unknown&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ModelName &quot;DELL U2211H&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    HorizSync 30.0 - 83.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    VertRefresh 56.0 - 76.0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;DPMS&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    #Option &quot;Rotate&quot; &quot;left&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Device&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Device0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Driver &quot;nvidia&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    VendorName &quot;NVIDIA Corporation&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    BoardName &quot;GeForce GTX 550 Ti&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    BusID &quot;PCI:1:0:0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    #Option &quot;RandRRotation&quot; &quot;on&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Screen 0
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Device&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Device1&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Driver &quot;nvidia&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    VendorName &quot;NVIDIA Corporation&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    BoardName &quot;GeForce GTX 550 Ti&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    BusID &quot;PCI:1:0:0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    #Option &quot;RandRRotation&quot; &quot;on&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Screen 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Screen&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Screen0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Device &quot;Device0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Monitor &quot;Monitor0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    DefaultDepth 24
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;TwinView&quot; &quot;0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;metamodes&quot; &quot;DFP-0: nvidia-auto-select +0+0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    SubSection &quot;Display&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        Depth 24
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    EndSubSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;Section &quot;Screen&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Identifier &quot;Screen1&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Device &quot;Device1&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Monitor &quot;Monitor1&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    DefaultDepth 24
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;TwinView&quot; &quot;0&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;metamodes&quot; &quot;DFP-2: nvidia-auto-select +0+0 { Rotation=left }&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    Option &quot;Rotate&quot; &quot;cw&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    SubSection &quot;Display&quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        Depth 24
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    EndSubSection
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;EndSection
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Programs&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Programs&quot; class=&quot;heading-ref&quot;&gt;Programs&lt;/a&gt;&lt;/h2&gt;
&lt;section id=&quot;Firefox&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Firefox&quot; class=&quot;heading-ref&quot;&gt;Firefox&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Download latest&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;tar&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; xf ...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;mv&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; firefox /usr/local/lib64/&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; /usr/bin&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;rm&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; firefox&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; /usr/local/lib64/firefox/firefox .&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Get &lt;code&gt;libflashplayer.so&lt;/code&gt; into &lt;code&gt;/usr/local/lib64/firefox/browser/plugins&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Restore bookmark backup from &lt;code&gt;.mozilla/firefox/X.default/bookmarkbackups&lt;/code&gt; if you want.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;vim&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#vim&quot; class=&quot;heading-ref&quot;&gt;vim&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For xterm copying and support for more plugins. Get vim source.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;hg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; clone https://vim.googlecode.com/hg/ vim&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; vim&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;./configure&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; --&lt;/span&gt;with-features&lt;/span&gt;&lt;span class=&quot;keyword operator assignment option shell&quot;&gt;=&lt;/span&gt;huge &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;enable-multibyte&lt;/span&gt; &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;enable-rubyinterp&lt;/span&gt; &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;enable-pythoninterp&lt;/span&gt; &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;enable-perlinterp&lt;/span&gt; &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;enable-luainterp&lt;/span&gt; &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;prefix&lt;/span&gt;&lt;span class=&quot;keyword operator assignment option shell&quot;&gt;=&lt;/span&gt;/usr/local &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;enable-gui&lt;/span&gt; &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;enable-hangulinput&lt;/span&gt; &lt;span class=&quot;punctuation separator continuation line shell&quot;&gt;\
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt;            --&lt;/span&gt;with-x&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;make&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Skype&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Skype&quot; class=&quot;heading-ref&quot;&gt;Skype&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install [Multilib]. Install skype from slackbuilds, use 32bit mode.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Spotify&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Spotify&quot; class=&quot;heading-ref&quot;&gt;Spotify&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install [Multilib]. Fetch from slackbuilds. I’m having some flickering issues, but no idea what to do.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Office&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Office&quot; class=&quot;heading-ref&quot;&gt;Office&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install [Java]. Install &lt;code&gt;libreoffice&lt;/code&gt; from slackbuilds.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;cron&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#cron&quot; class=&quot;heading-ref&quot;&gt;cron&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;crontab -e&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;# Every 5 minutes
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;*/5 * * * * /home/tree/bin/ticker --update
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Appearance&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Appearance&quot; class=&quot;heading-ref&quot;&gt;Appearance&lt;/a&gt;&lt;/h2&gt;
&lt;section id=&quot;xmonad&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#xmonad&quot; class=&quot;heading-ref&quot;&gt;xmonad&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
Install ghc linked from slackbuilds
&lt;/li&gt;
&lt;li&gt;
Install hscolour from slackbuilds (for haskell-platform warnings)
&lt;/li&gt;
&lt;li&gt;
Install haskell-platform from slackbuilds
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As user:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; update&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install cabal-install&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install xmonad&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install xmonad-contrib&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; dotfiles/.xmonad &lt;span class=&quot;meta group expansion tilde&quot;&gt;&lt;span class=&quot;variable language tilde shell&quot;&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Install &lt;code&gt;conky&lt;/code&gt; with dependencies from slackbuilds. Build conky with lua support.&lt;/p&gt;
&lt;p&gt;Install &lt;code&gt;dzen2&lt;/code&gt; by cloning from github. Edit &lt;code&gt;config.mk&lt;/code&gt;, choose option 7 (XPM, XFT, Xinerama).&lt;/p&gt;
&lt;p&gt;Get &lt;code&gt;.backgrounds&lt;/code&gt; and &lt;code&gt;.icons&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Could not get nitrogen to build properly (I stole it from my other installation…!!)&lt;/p&gt;
&lt;p&gt;Fix borders on firefox etc with &lt;code&gt;lxappearance&lt;/code&gt;, install from slackbuilds.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Fonts&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Fonts&quot; class=&quot;heading-ref&quot;&gt;Fonts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Copy ttf fonts to &lt;code&gt;/usr/share/fonts/TTF&lt;/code&gt;, in that dir run&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;mkfontscale&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;mkfontdir&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;fc-cache&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;fv&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In &lt;code&gt;/usr/bin/startx&lt;/code&gt; mod a line with &lt;code&gt;defaultserverargs=&quot;-dpi 96&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From &lt;a href=&quot;http://www.linuxquestions.org/questions/slackware-14/how-to-optimize-fonts-in-slackware-640468/page29.html#post5067546&quot;&gt;http://www.linuxquestions.org/questions/slackware-14/how-to-optimize-fonts-in-slackware-640468/page29.html#post5067546&lt;/a&gt;, &lt;a href=&quot;http://blog.lysender.com/2013/11/optimizing-fonts-for-slackware-14-1-without-infinality/&quot;&gt;http://blog.lysender.com/2013/11/optimizing-fonts-for-slackware-14-1-without-infinality/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Enable subpixel rendering from source slackbuild &lt;a href=&quot;http://ftp.slackware.com/pub/slackware/slackware-14.1/source/l/freetype/&quot;&gt;http://ftp.slackware.com/pub/slackware/slackware-14.1/source/l/freetype/&lt;/a&gt;. Edit freetype.Slackbuild&lt;/p&gt;
&lt;p&gt;Save as &lt;code&gt;freetype_cleartype.diff&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;diff&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight diff&quot;&gt;&lt;div class=&quot;line&quot;&gt;diff -rupN freetype.orig/cleartype.diff freetype/cleartype.diff
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta diff header from-file&quot;&gt;&lt;span class=&quot;punctuation definition from-file diff&quot;&gt;---&lt;/span&gt; freetype.orig/cleartype.diff	1969-12-31 16:00:00.000000000 -0800
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta diff header to-file&quot;&gt;&lt;span class=&quot;punctuation definition to-file diff&quot;&gt;+++&lt;/span&gt; freetype/cleartype.diff	2013-11-19 15:32:04.811346576 -0800
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta diff range unified&quot;&gt;&lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;meta toc-list line-number diff&quot;&gt;-0,0 +1,12&lt;/span&gt; &lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;diff -rupN freetype-2.5.0.1.orig/include/freetype/config/ftoption.h freetype-2.5.0.1/include/freetype/config/ftoption.h
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;--- freetype-2.5.0.1.orig/include/freetype/config/ftoption.h	2013-06-19 14:20:04.000000000 -0700
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;+++ freetype-2.5.0.1/include/freetype/config/ftoption.h	2013-11-19 15:27:47.456737625 -0800
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;@@ -591,7 +591,7 @@ FT_BEGIN_HEADER
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;   /*   This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be    */
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;   /*   defined.                                                            */
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;   /*                                                                       */
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;+#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt; 
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt; 
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;   /*************************************************************************/
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;diff -rupN freetype.orig/freetype.SlackBuild freetype/freetype.SlackBuild
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta diff header from-file&quot;&gt;&lt;span class=&quot;punctuation definition from-file diff&quot;&gt;---&lt;/span&gt; freetype.orig/freetype.SlackBuild	2013-11-19 15:31:53.895891885 -0800
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta diff header to-file&quot;&gt;&lt;span class=&quot;punctuation definition to-file diff&quot;&gt;+++&lt;/span&gt; freetype/freetype.SlackBuild	2013-11-19 15:33:17.885864416 -0800
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta diff range unified&quot;&gt;&lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;meta toc-list line-number diff&quot;&gt;-78,7 +78,8&lt;/span&gt; &lt;span class=&quot;punctuation definition range diff&quot;&gt;@@&lt;/span&gt;&lt;/span&gt; zcat $CWD/freetype.illadvisederror.diff.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; # for doing so.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; # Please see this web site for more details:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; #   http://www.freetype.org/patents.html
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;markup deleted diff&quot;&gt;&lt;span class=&quot;punctuation definition deleted diff&quot;&gt;-&lt;/span&gt;#zcat $CWD/freetype.subpixel.rendering.diff.gz | patch -p1 --verbose || exit 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;zcat $CWD/freetype.subpixel.rendering.diff.gz | patch -p1 --verbose || exit 1
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;markup inserted diff&quot;&gt;&lt;span class=&quot;punctuation definition inserted diff&quot;&gt;+&lt;/span&gt;patch -p1 --verbose &amp;lt; $CWD/cleartype.diff
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt; 
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; chown -R root:root .
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; CFLAGS=&amp;quot;$SLKCFLAGS&amp;quot; make setup CFG=&amp;quot;--prefix=/usr --libdir=/usr/lib${LIBDIRSUFFIX} --build=$ARCH-slackware-linux&amp;quot;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;lftp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;c&lt;/span&gt; &lt;span class=&quot;string quoted single shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;#39;&lt;/span&gt;open ftp.slackware.com ; mirror pub/slackware/slackware64-14.1/source/l/freetype/&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;support function cd shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; freetype&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;patch&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;p1&lt;/span&gt; &lt;span class=&quot;keyword operator assignment redirection shell&quot;&gt;&amp;lt;&lt;/span&gt; ../freetype_cleartype.diff&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;./freetype.SlackBuild&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;removepkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; freetype-2.5.0.1-x86_64-1&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;installpkg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; /tmp/freetype-2.5.0.1-x86_64-1.txz&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enable subpixel rendering. Test &lt;a href=&quot;http://www.lagom.nl/lcd-test/subpixel.php&quot;&gt;http://www.lagom.nl/lcd-test/subpixel.php&lt;/a&gt;, choose rgb, gbr, or whatever. Also useful: &lt;a href=&quot;https://wiki.archlinux.org/index.php/Font_configuration&quot;&gt;https://wiki.archlinux.org/index.php/Font_configuration&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; /etc/fonts/conf.avail/10-sub-pixel-rgb.conf /etc/fonts/conf.d&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; /etc/fonts/conf.avail/11-lcdfilter-default.conf /etc/fonts/conf.d&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also use &lt;code&gt;~/.config/fontconfig/fonts.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;xml&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight xml&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag preprocessor xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;entity name tag xml&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted single xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;#39;&lt;/span&gt;1.0&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag sgml doctype xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;keyword doctype xml&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;variable documentroot xml&quot;&gt;fontconfig&lt;/span&gt; SYSTEM &amp;#39;fonts.dtd&amp;#39;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;fontconfig&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;	&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;font&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;antialias&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;true&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hinting&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;true&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintslight&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; Ignore any embedded bitmaps in TTF, etc (Microsoft&amp;#39;s Calibri and others from Office 07/Vista have these) &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;embeddedbitmap&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;false&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;comment block xml&quot;&gt;&lt;span class=&quot;punctuation definition comment begin xml&quot;&gt;&amp;lt;!--&lt;/span&gt; MS fonts use full hinting &lt;span class=&quot;punctuation definition comment end xml&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Andale Mono&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Arial&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Arial Black&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Calibri&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Cambria&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Candara&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Comic Sans MS&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Consolas&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Constantia&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Corbel&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Courier New&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Georgia&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Impact&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Symbol&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Tahoma&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Times New Roman&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Trebuchet MS&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Verdana&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Webdings&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;family&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Wingdings&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;assign&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity other attribute-name localname xml&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;punctuation separator key-value xml&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;string quoted double xml&quot;&gt;&lt;span class=&quot;punctuation definition string begin xml&quot;&gt;&amp;quot;&lt;/span&gt;hintstyle&lt;span class=&quot;punctuation definition string end xml&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;			&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;hintfull&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;		&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;	&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta tag xml&quot;&gt;&lt;span class=&quot;punctuation definition tag begin xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity name tag localname xml&quot;&gt;fontconfig&lt;/span&gt;&lt;span class=&quot;punctuation definition tag end xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Terminal&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Terminal&quot; class=&quot;heading-ref&quot;&gt;Terminal&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Fetch &lt;code&gt;rxvt-unicode&lt;/code&gt; from slackbuilds. Make &lt;code&gt;.Xresources&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Color schemes with ls listings will be ugly, so copy &lt;code&gt;DIR_COLORS&lt;/code&gt; to &lt;code&gt;.dir_colors&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;C&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight C&quot;&gt;&lt;div class=&quot;line&quot;&gt;STICKY_OTHER_WRITABLE &lt;span class=&quot;constant numeric c&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;constant numeric c&quot;&gt;40&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;OTHER_WRITABLE &lt;span class=&quot;constant numeric c&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;punctuation terminator c&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;constant numeric c&quot;&gt;40&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Set in .zshrc.&lt;/p&gt;
&lt;p&gt;Fix git diff colors &lt;code&gt;git config --global core.pager &quot;less -r&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Also korean signs.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Random-Installs&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Random-Installs&quot; class=&quot;heading-ref&quot;&gt;Random Installs&lt;/a&gt;&lt;/h2&gt;
&lt;section id=&quot;Slackbuilds&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Slackbuilds&quot; class=&quot;heading-ref&quot;&gt;Slackbuilds&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Download from &lt;a href=&quot;http://slackbuilds.org/&quot;&gt;http://slackbuilds.org/&lt;/a&gt;. Install with &lt;code&gt;installpkg&lt;/code&gt;. Remove with &lt;code&gt;removepkg&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;s3cmd, scrot, mirage, rtorrent
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Perl&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Perl&quot; class=&quot;heading-ref&quot;&gt;Perl&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install perl libs from cpan. As root:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install cpan&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install App::Ack&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install Modern::Perl&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install DateTime&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install Data::ICal&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cpan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install LWP&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; And possibly other things&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section id=&quot;Multilib&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Multilib&quot; class=&quot;heading-ref&quot;&gt;Multilib&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://alien.slackbook.org/dokuwiki/doku.php?id=slackware:multilib&quot;&gt;http://alien.slackbook.org/dokuwiki/doku.php?id=slackware:multilib&lt;/a&gt; Also add blacklist.&lt;/p&gt;
&lt;p&gt;When installing 32bit run &lt;code&gt;. /etc/profile.d/32dev.sh&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Better-latex&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Better-latex&quot; class=&quot;heading-ref&quot;&gt;Better latex&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install &lt;code&gt;texlive&lt;/code&gt; from slackbuilds. Remove &lt;code&gt;tetex&lt;/code&gt; first.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Groovebasin&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Groovebasin&quot; class=&quot;heading-ref&quot;&gt;Groovebasin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Need &lt;code&gt;libgroove&lt;/code&gt;.  Which also needs &lt;code&gt;speex&lt;/code&gt; from slackbuilds apart from the clear dependencies. Run groovebasin as user.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Java&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Java&quot; class=&quot;heading-ref&quot;&gt;Java&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get &lt;code&gt;OpenAL&lt;/code&gt; from slackbuilds.  Get Java JDK &lt;a href=&quot;http://docs.slackware.com/howtos:software:java&quot;&gt;http://docs.slackware.com/howtos:software:java&lt;/a&gt;, not OpenJDK.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Anki&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Anki&quot; class=&quot;heading-ref&quot;&gt;Anki&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Download anki.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;mv anki-2.0.26 /usr/local/lib64
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ln -s /usr/local/lib64/anki-2.0.26/runanki /usr/local/bin
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Programming&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Programming&quot; class=&quot;heading-ref&quot;&gt;Programming&lt;/a&gt;&lt;/h2&gt;
&lt;section id=&quot;Hakyll&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Hakyll&quot; class=&quot;heading-ref&quot;&gt;Hakyll&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install hakyll&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;cabal&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; install MissingH&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For upload scripts fetch &lt;code&gt;python-magic&lt;/code&gt; slackbuilds.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;SFML&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#SFML&quot; class=&quot;heading-ref&quot;&gt;SFML&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get source. &lt;code&gt;cmake&lt;/code&gt; and install.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Games&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Games&quot; class=&quot;heading-ref&quot;&gt;Games&lt;/a&gt;&lt;/h2&gt;
&lt;section id=&quot;Minecraft&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Minecraft&quot; class=&quot;heading-ref&quot;&gt;Minecraft&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Requires [Java]. Launch with:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;java&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;Xmx2048M&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;Xms1024M&lt;/span&gt;&lt;span class=&quot;variable parameter option shell&quot;&gt;&lt;span class=&quot;punctuation definition parameter shell&quot;&gt; -&lt;/span&gt;jar&lt;/span&gt; &lt;span class=&quot;meta group expansion tilde&quot;&gt;&lt;span class=&quot;variable language tilde shell&quot;&gt;~&lt;/span&gt;&lt;/span&gt;/.minecraft/launcher/Minecraft.jar&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I copied &lt;code&gt;.minecraft&lt;/code&gt; folder with saves etc.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
</content></entry><entry><title>Notifications with xmonad/irssi/urxvt</title><id>http://jonashietala.se/blog/2014/07/03/notifications/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/07/03/notifications" rel="alternate"/><published>2014-07-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I’ve been idling on irc for years now and I’ve been using &lt;a href=&quot;http://www.irssi.org/&quot; title=&quot;irssi&quot;&gt;irssi&lt;/a&gt; for that, which works fine. I have not had notifications enabled, so I can see from the statusbar whenever someone messages me. As I’ve never been very active this has been fine, but now I figured it’s time to fix that.&lt;/p&gt;
&lt;p&gt;Fortunately it was very easy, there’s even a perfect match for my setup in the &lt;a href=&quot;http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Hooks-UrgencyHook.html&quot; title=&quot;xmonad documentation&quot;&gt;xmonad documentation&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Here’s a summary:&lt;/p&gt;
&lt;h1&gt;Configure xmonad&lt;/h1&gt;
&lt;p&gt;In &lt;code&gt;xmonad.hs&lt;/code&gt;, highlight with existing dzen (my statusbar).&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;myDzenPP h &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; defaultPP { &lt;span class=&quot;keyword operator haskell&quot;&gt;...&lt;/span&gt; }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;main &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control haskell&quot;&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    bar &lt;span class=&quot;keyword operator haskell&quot;&gt;&amp;lt;-&lt;/span&gt; spawnPipe &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;dzen2 ...&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    xmonad &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; withUrgencyHook &lt;span class=&quot;constant other haskell&quot;&gt;NoUrgencyHook&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; defaultConfig {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        logHook &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; dynamicLogWithPP &lt;span class=&quot;keyword operator haskell&quot;&gt;$&lt;/span&gt; myDzenPP bar
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator haskell&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    }
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Configure irssi&lt;/h1&gt;
&lt;p&gt;I used &lt;a href=&quot;http://jerith.za.net/code/irssichanbeep.html&quot; title=&quot;beepchan.pl&quot;&gt;beepchan.pl&lt;/a&gt; to only notify on selected channels.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;bash&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;settings&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; = &lt;span class=&quot;meta group expansion brace shell&quot;&gt;&lt;span class=&quot;punctuation section expansion brace begin shell&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;fe-common/core&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; = &lt;span class=&quot;meta group expansion brace shell&quot;&gt;&lt;span class=&quot;punctuation section expansion brace begin shell&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    bell_beeps = &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;yes&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    beep_msg_level = &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;MSGS NOTICES INVITES DCC DCCMSGS HILIGHT&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    beep_when_away = &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;no&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    beep_when_window_active = &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;no&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section expansion brace end shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;perl/core/scripts&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; = &lt;span class=&quot;meta group expansion brace shell&quot;&gt;&lt;span class=&quot;punctuation section expansion brace begin shell&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    beep_channels = &lt;span class=&quot;string quoted double shell&quot;&gt;&lt;span class=&quot;punctuation definition string begin shell&quot;&gt;&amp;quot;&lt;/span&gt;#treecraft&lt;span class=&quot;punctuation definition string end shell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    ...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;  &lt;span class=&quot;punctuation section expansion brace end shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;punctuation section expansion brace end shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator logical continue shell&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Configure screen&lt;/h1&gt;
&lt;p&gt;In &lt;code&gt;.screenrc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;vbell&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; off &lt;span class=&quot;comment line number-sign shell&quot;&gt;&lt;span class=&quot;punctuation definition comment begin shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign shell&quot;&gt; or remove the existing &amp;#39;vbell on&amp;#39; line&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;Configure rxvt&lt;/h1&gt;
&lt;p&gt;In &lt;code&gt;.Xdefaults&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;highlight bash&quot;&gt;&lt;span class=&quot;meta function-call shell&quot;&gt;&lt;span class=&quot;variable function shell&quot;&gt;urxvt.urgentOnBell:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function-call arguments shell&quot;&gt; true&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
</content></entry><entry><title>Calling closures in a Vec</title><id>http://jonashietala.se/blog/2014/06/21/calling_closures_in_a_vec/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/06/21/calling_closures_in_a_vec" rel="alternate"/><published>2014-06-21T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;In rust one might want to have a list of closures, for example as a list of callbacks.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; fs&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Vec&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;invalid illegal rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support type rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;fs.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;imma firing my lazer&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; f &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; fs.&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support function rust&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; error: expected function but found `&amp;amp;||`
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Maybe if we borrow f?&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;f &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; fs.&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; error: cannot move out of dereference of `&amp;amp;`-pointer```
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;support function rust&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But then if we dereference f?&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; f &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; fs.&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; error: closure invocation in a `&amp;amp;` reference
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s not very helpful. Thanks to some friendly guys over at &lt;code&gt;#rust&lt;/code&gt; at &lt;code&gt;irc.mozilla.org&lt;/code&gt; I found something which works:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; f &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; fs.&lt;span class=&quot;support function rust&quot;&gt;mut_iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; ok!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A note is that the closure types must be &lt;code&gt;&amp;amp;mut ||&lt;/code&gt; and not &lt;code&gt;&amp;amp;||&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the end I think that the error messages could be more clear. But now we have a running example and all is well in the world!&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Print &amp;quot;imma firing my lazer&amp;quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; fs&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta generic rust&quot;&gt;Vec&lt;span class=&quot;punctuation definition generic begin rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;invalid illegal rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support type rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    fs.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function closure rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;imma firing my lazer&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; f &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; fs.&lt;span class=&quot;support function rust&quot;&gt;mut_iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; ok!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>addwatch: resource exhausted</title><id>http://jonashietala.se/blog/2014/06/13/addwatch_resource_exhausted/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/06/13/addwatch_resource_exhausted" rel="alternate"/><published>2014-06-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;While tampering with Hakyll and running &lt;code&gt;site preview&lt;/code&gt; I stumbled upon this error message:&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;site: addWatch: resource exhausted (No space left on device)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At first I tried to clear &lt;code&gt;/tmp&lt;/code&gt; but, so clearly the device did have some space left. After a bit of googling I found &lt;a href=&quot;http://peter-butkovic.blogspot.se/2013/08/tail-inotify-resources-exhausted.html&quot;&gt;a solution&lt;/a&gt; which managed to solve my problem.&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;# for foo in /proc/*/fd/*; do readlink -f $foo; done | grep inotify | sort | uniq -c | sort -nr
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      2 /proc/12871/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/673/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/601/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/587/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/27695/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/176/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12879/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12840/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12806/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12772/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12771/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12770/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12769/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12768/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12767/fd/anon_inode:inotify
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;      1 /proc/12754/fd/anon_inode:inotify
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One can examine the pid&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=&quot;line&quot;&gt;ps ax
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;ps ax | grep 12871
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;...
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And in the end I found out that spotify was the culprit. I killed the spotify processes with a simple &lt;code&gt;kill 12871&lt;/code&gt; and the problem had gone away.  One can check if spotify is running with &lt;code&gt;ps ax | grep spotify&lt;/code&gt;.&lt;/p&gt;
</content></entry><entry><title>IDA Summer of Code 2014</title><id>http://jonashietala.se/blog/2014/06/11/isoc/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/06/11/isoc" rel="alternate"/><published>2014-06-11T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;a href=&quot;http://www.ida.liu.se/projects/isoc/&quot; title=&quot;IDA Summer of Code&quot;&gt;IDA Summer of Code&lt;/a&gt; is &lt;a href=&quot;http://www.liu.se/&quot; title=&quot;LiU&quot;&gt;Linköping University’s&lt;/a&gt; response to &lt;a href=&quot;http://www.google-melange.com/gsoc/homepage/google/gsoc2014?PageSpeed=noscript&quot; title=&quot;Google Summer of Code&quot;&gt;Google Summer of Code&lt;/a&gt;. Students can send in a project of their choice and if selected they get paid to work on it for 4 weeks during the summer. In return the university get to show off the students and their projects in marketing purposes.&lt;/p&gt;
&lt;p&gt;As I’m writing this, my application got accepted and I will work on &lt;a href=&quot;http://www.rust-lang.org/&quot; title=&quot;rust&quot;&gt;rust&lt;/a&gt; sometime during July/August. rust is mozilla’s new systems programming language focusing on safety and concurrency. I’m quite excited as one of my goals this year was to contribute, and now I will get paid to!&lt;/p&gt;
&lt;p&gt;I am not completely sure exactly what I’m going to do, but things will get clearer when I actually start working on it. I will also make occassional blog posts of my thoughts and progress as I start working on it. As of now I’m working on my other summer job at &lt;a href=&quot;http://www.configura.com/&quot; title=&quot;Configura&quot;&gt;Configura&lt;/a&gt;, which is also quite amazing and I should post a bit about that as well.&lt;/p&gt;
</content></entry><entry><title>Mining Incorporated (unfinished)</title><id>http://jonashietala.se/blog/2014/04/28/mining-incorporated/index.html</id><updated>2026-04-27T11:09:37+00:00</updated><link href="https://www.jonashietala.se/blog/2014/04/28/mining-incorporated" rel="alternate"/><published>2014-04-28T00:27:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;h1&gt;Download&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;/games/mining_incorporated_ld29_linux64.tgz&quot;&gt;Linux 64bit&lt;/a&gt;
&lt;a href=&quot;/games/mining_incorporated_ld29_win.zip&quot;&gt;Windows&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Timelapse&lt;/h1&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=NIbr-mLi4DU&quot;&gt;https://www.youtube.com/watch?v=NIbr-mLi4DU&lt;/a&gt;
&lt;p&gt;I made a very serious attempt at making a grand game for &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare 29&lt;/a&gt;. Unfortunately it was a far, far, too big of a game for me to be able to finish it in one weekend. But I had a great experience and was fun beating the procrastination devil for once.&lt;/p&gt;
&lt;p&gt;Anyways, this is the state of the game as it is now.&lt;/p&gt;
&lt;h1&gt;Mining Incorporated&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/ld29/screen1_thumb.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/ld29/screen2_thumb.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/ld29/screen3_thumb.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;How to play&lt;/h1&gt;
&lt;p&gt;Choose a room, drag to build things. You must build where the worker starts. If you want more workers you need to build more beds. They can be placed anywhere. To gain money you must build or mine on an ore patch.&lt;/p&gt;
&lt;h1&gt;Source&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/ld29&quot;&gt;https://codeberg.org/treeman/ld29&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>Ores</title><id>http://jonashietala.se/blog/2014/04/27/ores/index.html</id><updated>2023-10-01T13:22:41+00:00</updated><link href="https://www.jonashietala.se/blog/2014/04/27/ores" rel="alternate"/><published>2014-04-27T19:48:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Now we can build rooms, we can place objects and the worker will do things for us. Now I’ve added some ores which makes the game look a bit less boring. I realize I’ve spent all my time on these little things and I still don’t have a game! But it doesn’t matter, maybe I can finish the game on a later date.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ld29/ores.png&quot; /&gt;
&lt;figcaption&gt;Oooh, is that diamond?&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>We can build things!</title><id>http://jonashietala.se/blog/2014/04/27/canbuild/index.html</id><updated>2023-10-01T13:23:09+00:00</updated><link href="https://www.jonashietala.se/blog/2014/04/27/canbuild" rel="alternate"/><published>2014-04-27T11:12:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Finally we have some sort of progress!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ld29/can_build.png&quot; /&gt;
&lt;figcaption&gt;We can now build rooms and place and remove objects!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Yay!! But we still haven’t even begun with the game logic, resource management, the actual mining mechanic, multiple levels, actual tasks for our workers. But it’s something.&lt;/p&gt;
</content></entry><entry><title>Hard Work</title><id>http://jonashietala.se/blog/2014/04/26/hard-work/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/04/26/hard-work" rel="alternate"/><published>2014-04-26T21:25:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve spent literally the whole day coding and it feels like I’ve only done a small parts of the actual game mechanics… I know this isn’t going to end well.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ld29/hard_work.png&quot; alt=&quot;More Hard Work!&quot; /&gt;&lt;br /&gt;
&lt;em&gt;I can allow myself a small pause I feel…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Not sure where this is going to end, but I’m having a blast anyway!&lt;/p&gt;
</content></entry><entry><title>An Epic Start</title><id>http://jonashietala.se/blog/2014/04/26/an-epic-start/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/04/26/an-epic-start" rel="alternate"/><published>2014-04-26T07:07:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Oh what a mistake. I woke up at 05.00 when my girlfriend woke up, she’s working early today, and went to the bathroom. After I was done, still pretty tired, I made a big mistake. I checked the current theme for Ludum Dare 29: &lt;strong&gt;Beneath the Surface&lt;/strong&gt; and guess what? Now I wasn’t tired anymore.&lt;/p&gt;
&lt;p&gt;So I got out of bed, at 5!, and wrote down some ideas. Now, almost 2 hours later, I’ve had a battle with my makefile and I’ve written a lazy resource management system and a simple state transition scheme. A bit annoying as my previous fast prototyping framework already had all those ready, but in the end I got a bunch of coding done and it’s not that big of a deal anyways.&lt;/p&gt;
&lt;p&gt;My idea for the theme is far too big of course. Hopefully I’ll have something to show off in the end. But now I need to eat some breakfast and maybe go sleep an hour or two…&lt;/p&gt;
</content></entry><entry><title>A *</title><id>http://jonashietala.se/blog/2014/04/26/astar/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/04/26/astar" rel="alternate"/><published>2014-04-26T07:07:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After a few hours of coding I’ve made a little, little, bit of progress but it took a lot longer than I would have liked.&lt;/p&gt;
&lt;p&gt;I’ve basically managed to make a world and some tiles in the world and we have a worker who can move around on the tiles and he can’t move on all tiles.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ld29/astar.png&quot; alt=&quot;A*&quot; /&gt;&lt;br /&gt;
&lt;em&gt;Look! He can pathfind! But here the real coding begins…&lt;/em&gt;&lt;/p&gt;
</content></entry><entry><title>Ludum Dare 29 Entry</title><id>http://jonashietala.se/blog/2014/04/25/ludum_dare_29_entry/index.html</id><updated>2026-04-27T11:09:44+00:00</updated><link href="https://www.jonashietala.se/blog/2014/04/25/ludum_dare_29_entry" rel="alternate"/><published>2014-04-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After months of procrastination it is time for me to enter &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare&lt;/a&gt; again!&lt;/p&gt;
&lt;p&gt;I am totally unprepared, but I did setup a setup which actually compiles. I never got audio to run but hopefully I can manage something.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href=&quot;https://codeberg.org/treeman/LD29&quot;&gt;https://codeberg.org/treeman/LD29&lt;/a&gt;. Going for C++ this time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graphics library:&lt;/strong&gt; &lt;a href=&quot;http://www.sfml-dev.org/&quot;&gt;SFML&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sound effects:&lt;/strong&gt; &lt;a href=&quot;http://www.drpetter.se/project_sfxr.html&quot;&gt;sfxr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graphics:&lt;/strong&gt; &lt;a href=&quot;http://mtpaint.sourceforge.net/&quot;&gt;mtpaint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timelapse hack:&lt;/strong&gt; &lt;a href=&quot;https://github.com/treeman/Timelapse&quot;&gt;https://github.com/treeman/Timelapse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I halted all school work and the whole weekend is booked, except for Taekwon-do on Sunday. Hopefully I’ll get something done!&lt;/p&gt;
</content></entry><entry><title>8-puzzle in rust</title><id>http://jonashietala.se/blog/2014/01/21/8-puzzle_in_rust/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2014/01/21/8-puzzle_in_rust" rel="alternate"/><published>2014-01-21T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I think &lt;a href=&quot;http://www.rust-lang.org/&quot;&gt;rust&lt;/a&gt; is one of the most interesting upcoming programming languages out there. So I wrote a solution to the 8-puzzle (see the &lt;a href=&quot;http://en.wikipedia.org/wiki/15_puzzle&quot;&gt;15-puzzle&lt;/a&gt;) using A*. It also has a breadth first search for solutions on a specific distance away from the goal.&lt;/p&gt;
&lt;p&gt;The solution is not by any means a great one and there are parts I’m a bit annoyed with, but that’s mostly because of my inexperience with rust.&lt;/p&gt;
&lt;p&gt;Rust was surprisingly easy to use and I like the strong typing and the pattern matching. One feature I found very useful was to do &lt;code&gt;println!(&quot;{:?}&quot;, x);&lt;/code&gt; and be able to print any variable, composite or not.&lt;/p&gt;
&lt;p&gt;I’m not friends with the different storage containers and especially the moving of values. Often I called a function with a value, but then I couldn’t reuse the value in another, so I ended up using &lt;code&gt;clone()&lt;/code&gt; a bunch. I’m probably abusing it and there’s bound to be a better way to do things.&lt;/p&gt;
&lt;p&gt;I got a little stumped on the standard library and spent some time perusing the documentation. It was very light on examples, which I find is the by far most useful thing to have in documentation, and I couldn’t even find some of the things. But it all worked out with a bit of determination.&lt;/p&gt;
&lt;p&gt;I should mention that I’m using rust master, not a stable release, and I’m well aware of rust being in development at the moment. Still things worked out fine and I quite enjoyed dabbling with rust. I’ll write some more in it I think.&lt;/p&gt;
&lt;p&gt;This is the code, working on &lt;code&gt;rustc 0.10-pre (5512fb4 2014-01-19 05:56:35 -0800)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;rust&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight rust&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment block documentation rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;/**
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt; * A solution to the 8-tiles puzzle, implemented in rust
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; * as a learning experience.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt; &lt;span class=&quot;punctuation definition comment rust&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;meta module rust&quot;&gt;&lt;span class=&quot;storage type module rust&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;entity name module rust&quot;&gt;extra&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;num&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;abs&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;hashmap&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;HashMap&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;std&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;hashmap&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;HashSet&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;extra&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;priority_queue&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;PriorityQueue&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;extra&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;container&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Deque&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword other rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;extra&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;ringbuf&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;RingBuf&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Use manhattan distance as heuristic for A*.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Sum of distance in x and distance in y for all tiles.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;manhattan&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;[int], &lt;span class=&quot;variable parameter rust&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;[int]&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; uint&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; dist&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; start.&lt;span class=&quot;support function rust&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; dest.&lt;span class=&quot;support function rust&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; start&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; dest&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; x1 &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; int &lt;span class=&quot;keyword operator rust&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; y1 &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; int &lt;span class=&quot;keyword operator rust&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; x2 &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; j &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; int &lt;span class=&quot;keyword operator rust&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; y2 &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; j &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; int &lt;span class=&quot;keyword operator rust&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                dist &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;x2 &lt;span class=&quot;keyword operator rust&quot;&gt;-&lt;/span&gt; x1&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; uint&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                dist &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;y2 &lt;span class=&quot;keyword operator rust&quot;&gt;-&lt;/span&gt; y1&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;as&lt;/span&gt; uint&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Avoid double counting so we don&amp;#39;t overestimate.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    dist &lt;span class=&quot;keyword operator rust&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;to_hash&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;[int]&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;storage type rust&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; hash &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; state.&lt;span class=&quot;support function rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        hash.&lt;span class=&quot;support function rust&quot;&gt;push_str&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;x.&lt;span class=&quot;support function rust&quot;&gt;to_str&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    hash
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;dead_code&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;print_state&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;[int]&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support macro rust&quot;&gt;print!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; j&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;dead_code&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;print&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;[int], &lt;span class=&quot;variable parameter rust&quot;&gt;goal&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;[int]&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support macro rust&quot;&gt;print!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; j&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;print!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;-&amp;gt; &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;print!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;   &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support macro rust&quot;&gt;print!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; goal&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt; i &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; j&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; A* uses g: cost so far, h: manhattan distance to goal, f: g + h
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;storage type struct rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;entity name struct rust&quot;&gt;State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta struct rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; ~[int],
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;variable other member rust&quot;&gt;zero&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint,
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;storage type impl rust&quot;&gt;impl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;entity name impl rust&quot;&gt;State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; ~[int], &lt;span class=&quot;variable parameter rust&quot;&gt;goal&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; ~[int], &lt;span class=&quot;variable parameter rust&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint, &lt;span class=&quot;variable parameter rust&quot;&gt;zero&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; h &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;manhattan&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; goal&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        State &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; state&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; g&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; h&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; h&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; zero&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; zero &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Ignore h and f.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;new_simple&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; ~[int], &lt;span class=&quot;variable parameter rust&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint, &lt;span class=&quot;variable parameter rust&quot;&gt;zero&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        State &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; state&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; g&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; h&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; 0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; zero&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; zero &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; uint&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.g &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.h &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta annotation rust&quot;&gt;&lt;span class=&quot;punctuation definition annotation rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;variable annotation rust&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;dead_code&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta annotation parameters rust&quot;&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;print&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;g: &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; h: &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; f: &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.g&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.h&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support function rust&quot;&gt;print_state&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.state&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;storage type impl rust&quot;&gt;impl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;Ord &lt;span class=&quot;keyword other rust&quot;&gt;for&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt; &lt;span class=&quot;entity name impl rust&quot;&gt;State&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta impl rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;lt&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;self&lt;/span&gt;, &lt;span class=&quot;variable parameter rust&quot;&gt;s2&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;State&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;storage type rust&quot;&gt;bool&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;variable language rust&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;support function rust&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt; s2.&lt;span class=&quot;support function rust&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;static&lt;/span&gt; dx&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;uint&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;storage type rust&quot;&gt;static&lt;/span&gt; dy&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;uint&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Calculate the minimum distance from a state to goal with A*
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;dist&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; ~[int], &lt;span class=&quot;variable parameter rust&quot;&gt;goal&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; ~[int]&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; uint&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; dist &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;HashMap&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; q &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;PriorityQueue&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    dist.&lt;span class=&quot;support function rust&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function rust&quot;&gt;to_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;state&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; 0u&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; zero &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;match&lt;/span&gt; state.&lt;span class=&quot;support function rust&quot;&gt;position_elem&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support type rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;x&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; x&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support type rust&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;fail!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;0 missing in state!&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    q.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;State&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; goal.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; 0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; zero&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Ugly, but don&amp;#39;t know how...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; cost&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; pos&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;match&lt;/span&gt; q.&lt;span class=&quot;support function rust&quot;&gt;maybe_top&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support type rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;e&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;comment block rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;/*&lt;/span&gt;e.print();&lt;span class=&quot;punctuation definition comment rust&quot;&gt;*/&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;e.state.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; e.g&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; e.zero&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support type rust&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        q.&lt;span class=&quot;support function rust&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; state &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; goal &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;return&lt;/span&gt; cost&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; pos &lt;span class=&quot;keyword operator rust&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; y &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; pos &lt;span class=&quot;keyword operator rust&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; d &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; dx&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;d&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; ny &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; y &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; dy&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;d&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; ny &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; ny &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; npos &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt; ny&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; next_state &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; state.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            next_state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;pos&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; next_state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;npos&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            next_state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;npos&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; next_hash &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;to_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next_state&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; next_cost &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; cost &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;State&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next_state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; goal.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; next_cost&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; npos&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; s.state &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; goal &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;return&lt;/span&gt; next_cost&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;!&lt;/span&gt;dist.&lt;span class=&quot;support function rust&quot;&gt;contains_key&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;next_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; s.&lt;span class=&quot;support function rust&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt;dist.&lt;span class=&quot;support function rust&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;next_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                dist.&lt;span class=&quot;support function rust&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next_hash&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; next_cost&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                q.&lt;span class=&quot;support function rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    0u &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Should never happen!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Calculate the number of solutions with optimal solution length = target_dist.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Use breadth first.
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;num_dist_from&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable parameter rust&quot;&gt;goal&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; ~[int], &lt;span class=&quot;variable parameter rust&quot;&gt;target_dist&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;:&lt;/span&gt; uint&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;span class=&quot;meta function return-type rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;-&amp;gt;&lt;/span&gt; uint&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; count &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; 0u&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; seen &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;HashSet&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; q &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;RingBuf&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    seen.&lt;span class=&quot;support function rust&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;support function rust&quot;&gt;to_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;goal&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; zero &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;match&lt;/span&gt; goal.&lt;span class=&quot;support function rust&quot;&gt;position_elem&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support type rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;x&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; x&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;support type rust&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;support macro rust&quot;&gt;fail!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;0 missing in state!&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    q.&lt;span class=&quot;support function rust&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;meta path rust&quot;&gt;State&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new_simple&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;goal.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; 0u&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; zero&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword control rust&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;comment line double-slash rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;//&lt;/span&gt; Ugly, but don&amp;#39;t know how...
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; dist&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; pos&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;match&lt;/span&gt; q.&lt;span class=&quot;support function rust&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support type rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;e&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;comment block rust&quot;&gt;&lt;span class=&quot;punctuation definition comment rust&quot;&gt;/*&lt;/span&gt;e.print();&lt;span class=&quot;punctuation definition comment rust&quot;&gt;*/&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;e.state.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; e.g&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; e.zero&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;support type rust&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        q.&lt;span class=&quot;support function rust&quot;&gt;pop_front&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; dist &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt; target_dist &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; dist &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; target_dist &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; count &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; pos &lt;span class=&quot;keyword operator rust&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; y &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; pos &lt;span class=&quot;keyword operator rust&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;span class=&quot;keyword control rust&quot;&gt;for&lt;/span&gt; d &lt;span class=&quot;keyword operator rust&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; dx&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;d&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; ny &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; y &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; dy&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;d&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; ny &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;|&lt;/span&gt; ny &lt;span class=&quot;keyword operator rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;keyword control rust&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; npos &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; nx &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;*&lt;/span&gt; ny&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;storage modifier rust&quot;&gt;mut&lt;/span&gt; next_state &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; state.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            next_state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;pos&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; next_state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;npos&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            next_state&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;npos&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; next_hash &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;to_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next_state&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; next_dist &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; dist &lt;span class=&quot;keyword operator rust&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;meta path rust&quot;&gt;State&lt;span class=&quot;punctuation accessor rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new_simple&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next_state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; next_dist&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; npos&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;span class=&quot;keyword control rust&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;!&lt;/span&gt;seen.&lt;span class=&quot;support function rust&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword operator rust&quot;&gt;&amp;amp;&lt;/span&gt;next_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                seen.&lt;span class=&quot;support function rust&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;next_hash&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;                q.&lt;span class=&quot;support function rust&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;s&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    count
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;storage type function rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;entity name function rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta function parameters rust&quot;&gt;&lt;span class=&quot;punctuation section parameters end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;meta function rust&quot;&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block begin rust&quot;&gt;{&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; state &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; goal &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;keyword operator rust&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant numeric integer decimal rust&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support function rust&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; goal&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; sol &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; goal.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;optimal solution found in &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt; steps&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; sol&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;storage type rust&quot;&gt;let&lt;/span&gt; target_dist &lt;span class=&quot;keyword operator rust&quot;&gt;=&lt;/span&gt; sol&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;support macro rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;string quoted double rust&quot;&gt;&lt;span class=&quot;punctuation definition string begin rust&quot;&gt;&amp;quot;&lt;/span&gt;number of solutions on distance &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;: &lt;span class=&quot;constant other placeholder rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;punctuation definition string end rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; target_dist&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;support function rust&quot;&gt;num_dist_from&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;goal.&lt;span class=&quot;support function rust&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group begin rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation separator rust&quot;&gt;,&lt;/span&gt; target_dist&lt;/span&gt;&lt;span class=&quot;meta group rust&quot;&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation section group end rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation terminator rust&quot;&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta block rust&quot;&gt;&lt;span class=&quot;punctuation section block end rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content></entry><entry><title>2013 in Review</title><id>http://jonashietala.se/blog/2014/01/04/2013_in_review/index.html</id><updated>2026-04-27T11:09:59+00:00</updated><link href="https://www.jonashietala.se/blog/2014/01/04/2013_in_review" rel="alternate"/><published>2014-01-04T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The year is almost over and I think I accomplished a lot this year. You can read my reviews of &lt;a href=&quot;/blog/2011/01/06/2010_in_review/&quot;&gt;2010&lt;/a&gt;, &lt;a href=&quot;/blog/2012/01/04/2011_in_review/&quot;&gt;2011&lt;/a&gt; and &lt;a href=&quot;/blog/2012/12/31/2012_in_review/&quot;&gt;2012&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;2013 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Solved &lt;a href=&quot;http://uhunt.felix-halim.net/id/115705&quot;&gt;213 UVa problems&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Got 43rd at &lt;a href=&quot;https://chipcie.ch.tudelft.nl/&quot;&gt;NWERC 2013&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Placed high in &lt;a href=&quot;http://www.ida.liu.se/projects/impa/new/results&quot;&gt;IMPA&lt;/a&gt;, with one turn won.&lt;/li&gt;
&lt;li&gt;Completed the online course &lt;a href=&quot;https://class.coursera.org/proglang-002/class&quot;&gt;Programming Languages&lt;/a&gt; in Coursera.&lt;/li&gt;
&lt;li&gt;Wrote some ML, Racket and Ruby.&lt;/li&gt;
&lt;li&gt;Won the &lt;a href=&quot;http://www.ida.liu.se/~TDDD56/&quot;&gt;TDDD56&lt;/a&gt; Parallel Sorting Contest.&lt;/li&gt;
&lt;li&gt;Got my first summer job as a programmer at Configura. Great fun, great place to work.&lt;/li&gt;
&lt;li&gt;Wrote a lot of C and C++.&lt;/li&gt;
&lt;li&gt;Switched my &lt;a href=&quot;https://codeberg.org/treeman/jonashietala&quot;&gt;site&lt;/a&gt; generator from Jekyll to &lt;a href=&quot;http://jaspervdj.be/hakyll/&quot;&gt;Hakyll&lt;/a&gt; and wrote a little Haskell.&lt;/li&gt;
&lt;li&gt;For the first time achieved full marks in an exam - TDDD20 Construction and Analysis of Algorithms.&lt;/li&gt;
&lt;li&gt;Completed an extra math course: TATA64 Graph Theory. Fun course.&lt;/li&gt;
&lt;li&gt;Finished my 3 first years in University, now I can choose my own courses!&lt;/li&gt;
&lt;li&gt;Completed the compiler course in school and learned a bunch.&lt;/li&gt;
&lt;li&gt;Unlocked all ships in &lt;a href=&quot;http://www.ftlgame.com/&quot;&gt;FTL&lt;/a&gt; and beat it a bunch of times. Fantastic game!&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2013 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Had a good year with Veronica.&lt;/li&gt;
&lt;li&gt;Visited Karlskrona with Veronica.&lt;/li&gt;
&lt;li&gt;Achieved 4-kup in Taekwon-do.&lt;/li&gt;
&lt;li&gt;Been a kids trainer in Taekwon-do. Very rewarding.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2014/01/03/2013_read_books/&quot;&gt;Read 30 books&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Discovered &lt;a href=&quot;http://boardgamegeek.com/boardgame/31260/agricola&quot;&gt;Agricola&lt;/a&gt;, a great German Style board game.&lt;/li&gt;
&lt;li&gt;Discovered &lt;a href=&quot;http://boardgamegeek.com/boardgame/120677/terra-mystica&quot;&gt;Terra Mystica&lt;/a&gt;, another great board game.&lt;/li&gt;
&lt;li&gt;Did a bit of yoga.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2013 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Did not complete (or start) a hardware project.&lt;/li&gt;
&lt;li&gt;Did not achieve 3-kup in Taekwon-do.&lt;/li&gt;
&lt;li&gt;Did not participate in Ludum Dare.&lt;/li&gt;
&lt;li&gt;Missed two exams. I didn’t fail them, but I missed the dates…&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2014&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Take care of Veronica.&lt;/li&gt;
&lt;li&gt;Achieve 2-kup in Taekwon-do.&lt;/li&gt;
&lt;li&gt;Achieve a full split.&lt;/li&gt;
&lt;li&gt;Do 300 morning stretches.&lt;/li&gt;
&lt;li&gt;Visit the gym 100 times.&lt;/li&gt;
&lt;li&gt;Write a game.&lt;/li&gt;
&lt;li&gt;Participate in &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Code some rust.&lt;/li&gt;
&lt;li&gt;Read 31 books.&lt;/li&gt;
&lt;li&gt;Write 52 blog posts.&lt;/li&gt;
&lt;li&gt;Solve 100 UVa problems.&lt;/li&gt;
&lt;li&gt;Take more fun courses.&lt;/li&gt;
&lt;li&gt;Construct a custom keyboard.&lt;/li&gt;
&lt;li&gt;Successfully read 1 Korean speech bubble in Tower of God, without reference.&lt;/li&gt;
&lt;li&gt;Complete all exams.&lt;/li&gt;
&lt;li&gt;Prettify the site.&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>2013 Read Books</title><id>http://jonashietala.se/blog/2014/01/03/2013_read_books/index.html</id><updated>2023-10-01T13:21:51+00:00</updated><link href="https://www.jonashietala.se/blog/2014/01/03/2013_read_books" rel="alternate"/><published>2014-01-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I actually read more books in 2013 than in &lt;a href=&quot;/blog/2012/12/31/2012_read_books/&quot;&gt;2012&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In a somewhat unorganized list:&lt;/p&gt;
&lt;h1&gt;Fiction&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Livet Deluxe&lt;/strong&gt; - Jens Lapidius&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Escape from camp 14&lt;/strong&gt; - Blaine Harden&lt;/p&gt;
&lt;p&gt;Wonderful. A great book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Edge&lt;/strong&gt; - Jeffery Deaver&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dollar&lt;/strong&gt; - Lee Child&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gisslan&lt;/strong&gt; - Lee Child&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bränd&lt;/strong&gt; - Lee Child&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Besökaren&lt;/strong&gt; - Lee Child&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hetta&lt;/strong&gt; - Lee Child&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Värt att dö för&lt;/strong&gt; - Lee Child&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Livvakt&lt;/strong&gt; - Lee Child&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Non-fiction&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Graph Theory&lt;/strong&gt; - Reinhard Diestel&lt;/p&gt;
&lt;p&gt;Course book. Good but difficult.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Graph Theory With Applications&lt;/strong&gt; - Bondy and Murty&lt;/p&gt;
&lt;p&gt;Course book. Good explanations, but quite old (30 years).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modern Physics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Course book. Only read parts of it. Huge and wordy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Signals, Infomation and Communications&lt;/strong&gt; - Erik G. Larsson&lt;/p&gt;
&lt;p&gt;Course book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reglerteknik. Grundläggande teori&lt;/strong&gt; - Torkel Glad &amp;amp; Lennart Ljung&lt;/p&gt;
&lt;p&gt;Course book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Världens 99 bästa investerare&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Total Recall&lt;/strong&gt; - Arnold Schwarzenigger&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stora stretchboken&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Matrevolutionen&lt;/strong&gt; - Andreas Eenfeldt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kundaliniyoga&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stretching Scientifically&lt;/strong&gt; - Thomas Kurz&lt;/p&gt;
&lt;p&gt;By far the best book on stretching. (which I’ve read)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Statistics course book&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Don’t have the name atm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automata and Computability&lt;/strong&gt; - Kozen&lt;/p&gt;
&lt;p&gt;Course book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Artificial Intelligence&lt;/strong&gt; - Stuart Russell, Peter Norvig&lt;/p&gt;
&lt;p&gt;Course book. Selected chapters. Huge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Competitive Programming 3&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Introduction to Algorithms&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Course book. Only a few selected sections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compilers: Principles, techniques and tools&lt;/strong&gt; - Aho, Lam, Sethi, Ullman&lt;/p&gt;
&lt;p&gt;Course book. Read most of it without going in deep.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Numeriska beräkningar&lt;/strong&gt; - Eldén, Wittmeyer-Koch&lt;/p&gt;
&lt;p&gt;Course book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Love and Math&lt;/strong&gt; - Frenkel&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Children &amp;amp; Sports Training&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>Minecraft Server Hosting</title><id>http://jonashietala.se/blog/2013/04/22/minecraft_server/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2013/04/22/minecraft_server" rel="alternate"/><published>2013-04-22T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I play the phenomena that is Minecraft on and off. Sometimes the laid back building or the exploring is just what I need. Sometimes I can challange myself to build cool complex stuff and I’m even an avid follower of &lt;a href=&quot;https://www.youtube.com/channel/UC4O9HKe9Jt5yAhKuNv3LXpQ&quot;&gt;Doc’M&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/feed/UCFKDEp9si4RmHFWJW1vYsMA&quot;&gt;Etho&lt;/a&gt; and the other mindcrackers over at the youtube. Now brother Filip is an even more Minecraft follower than me and that’s the perfect setup for having my own minecraft server!&lt;/p&gt;
&lt;p&gt;For the last couple of months I’ve had a server running on &lt;a href=&quot;https://www.dotcloud.com/&quot;&gt;dotcloud&lt;/a&gt;’s sandboxed servers - it was literary free! A week or so ago they announced that they would turn off their sandboxed webapps and I had to turn my focus to something else.&lt;/p&gt;
&lt;p&gt;Enter dedicated minecraft hosting! The very first host I laid my eyes on (I didn’t even search for anything else) was &lt;a href=&quot;http://servercraft.co/&quot;&gt;servercraft&lt;/a&gt;. At $7.99/month I thought they where pretty cheap. &lt;em&gt;But they where pretty horrible&lt;/em&gt;. “Instant Minecraft Server setup in under 15 minutes!”. It took me about that long to get my first payment information and when I woke up that morning I could try out my new dedicated server.&lt;/p&gt;
&lt;p&gt;Or so I thought. I could see the server flickering between online/offline through Minecraft and I couldn’t connect reliably. But at least I could connect right? I’m sure it’ll work! Let’s upload our map through ftp. With their upload speed it took me about 30 minutes to get it done, and I have 100 Mbit upload. But now that’s done, who cares about that right? Let’s see if my brother can log in.&lt;/p&gt;
&lt;p&gt;Nope…&lt;/p&gt;
&lt;p&gt;Just for fun I browsed the &lt;a href=&quot;http://www.minecraftforum.net/&quot;&gt;minecraftforum&lt;/a&gt; and their &lt;a href=&quot;http://www.minecraftforum.net/forum/131-minecraft-server-hosting/&quot;&gt;dedicated server section&lt;/a&gt; if I could find something better. Preferrably something relatively cheap for about 5 players and hopefully with the ability to run &lt;a href=&quot;http://www.computercraft.info/&quot;&gt;Computercraft&lt;/a&gt;, a mod which allows you to program things. One of the most responded to threads was about &lt;a href=&quot;http://mcprohosting.com/&quot;&gt;MCProHosting&lt;/a&gt;. They offered a simple 5 player plan for $2.50/month and they seemed very active in the thread responding to queries and stuff. I decided to ask them if it would be possible to run a modded server and if they could help me set it up (I had no idea how to do it).&lt;/p&gt;
&lt;p&gt;A while later I’m running a perfectly smooth server with them, with up to 23 players and a total controll over the server’s mods and I’m practically paying the same as before ($9.99)! I had contact with two different people who helped answer my questions and to help me with my mod installing, they seemed very cunning and very service minded. &lt;strong&gt;&lt;a href=&quot;http://mcprohosting.com/&quot;&gt;MCProHosting&lt;/a&gt; has been fantastic so far.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;And about a day later servercraft responded to my unsubscribe mail (which I sent before looking elsewhere).&lt;/p&gt;
</content></entry><entry><title>FTL got a new victim</title><id>http://jonashietala.se/blog/2013/03/06/ftl_got_a_new_victim/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2013/03/06/ftl_got_a_new_victim" rel="alternate"/><published>2013-03-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;a href=&quot;http://www.ftlgame.com/&quot;&gt;Faster than Light&lt;/a&gt; the great game &lt;a href=&quot;/blog/2013/02/12/faster_than_light/&quot;&gt;I lost a ton of time on&lt;/a&gt;, has found a new victim. It’s not someone you’d expect, it’s even someone who said: “What a bad game” when she saw me playing it. But nevertheless this Saturday she played it more than 2.5 hours!&lt;/p&gt;
&lt;p&gt;I told Veronica I wanted her try out FTL and minecraft, but we never got time for minecraft… It was so funny seeing her, on the edge of the seat, mumbling “die, die, die” to herself when she’s in battle and jumping up “hooray!” when she destroyed the enemy. Sadly she didn’t beat the boss, but boy did she come close! FTL must be a hidden skill for her.&lt;/p&gt;
&lt;p&gt;I’m looking forward to introduce her to minecraft. I just hope she won’t get too addicted and turn into a clone of myself.&lt;/p&gt;
</content></entry><entry><title>Long Term Goals (part 2)</title><id>http://jonashietala.se/blog/2013/02/16/long_term_goals_part_2/index.html</id><updated>2023-10-01T13:38:27+00:00</updated><link href="https://www.jonashietala.se/blog/2013/02/16/long_term_goals_part_2" rel="alternate"/><published>2013-02-16T17:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A few minutes after I wrote about my long term goals, in the shower, I realize I forgot a few major goals I have:&lt;/p&gt;
&lt;h1&gt;Write my own Programming Language&lt;/h1&gt;
&lt;p&gt;Why? Because it sounds fun and epic as hell.&lt;/p&gt;
&lt;h1&gt;Write a Book&lt;/h1&gt;
&lt;p&gt;So I like books and I like to collect them and I have my whole bookcase filled with programming books, manga and fiction. Something really cool would be to have a book with &lt;em&gt;my name&lt;/em&gt; on it! So I wanna make that a reality.&lt;/p&gt;
&lt;p&gt;I think I wanna write a programming book, what else could I write about? Fiction? Nah, I don’t have enough imagination and my writing isn’t good enough for that. A self-biography? Nah, my life isn’t that interesting I’d say. Programming is fun and it’s something I feel relative confidence in, so I suppose that’s set then.&lt;/p&gt;
</content></entry><entry><title>Long Term Goals</title><id>http://jonashietala.se/blog/2013/02/16/long_term_goals/index.html</id><updated>2023-10-01T13:38:19+00:00</updated><link href="https://www.jonashietala.se/blog/2013/02/16/long_term_goals" rel="alternate"/><published>2013-02-16T10:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I have a lot of things I want to do. Right now I want to go to the kids training tomorrow and also to our training time. I haven’t trained a lot lately so it feels good to do something again and training the kids is very rewarding. On Monday I have the next graph theory lecture and I want to do all our lesson assignments until then. As I’ve beaten &lt;a href=&quot;/blog/2013/02/12/faster_than_light/&quot;&gt;FTL&lt;/a&gt; on easy I really want to do it on normal as well. And I’m looking forward going to the restaurant with Veronica and a bunch of other stuff.&lt;/p&gt;
&lt;p&gt;But sometimes it’s good to take a step back and take a look into the future a bit. What do I want to accomplish? What things do I want to do? What are my long term goals? This is an attempt to list some of them.&lt;/p&gt;
&lt;h1&gt;Black belt in Taekwon-do&lt;/h1&gt;
&lt;p&gt;I’ve been training for 2,5 years now and lately I’ve started to assist, and to hold, in the kids training and it’s great fun. Now this 3rd year in University the courses have become harder and I’ve also become more serious so the training has suffered a bit. But my long term goal with training has always been to have fun, maintain some shape and to get a black belt.&lt;/p&gt;
&lt;h1&gt;Contribute to a popular open-source project&lt;/h1&gt;
&lt;p&gt;I associate being a successful programmer and having contributed to, or started, a popular open-source project. I want to become a successful programmer, but that’s not really a concrete goal, so I want to get myself out there and contribute.&lt;/p&gt;
&lt;h1&gt;Own a Snooker table&lt;/h1&gt;
&lt;p&gt;This is a somewhat random goal to be sure. I love to watch snooker and I always try to catch the World Championship - but I have never played it! I’ve played some eight ball and I loved it, but no snooker, and I’m a bit sad that I haven’t played more. Somewhere there this goal was born.&lt;/p&gt;
&lt;h1&gt;I want to have kids&lt;/h1&gt;
&lt;p&gt;I love kids and sometime I want to have them too. More than one preferably.&lt;/p&gt;
</content></entry><entry><title>Faster than Light</title><id>http://jonashietala.se/blog/2013/02/12/faster_than_light/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2013/02/12/faster_than_light" rel="alternate"/><published>2013-02-12T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I returned to &lt;a href=&quot;http://www.ftlgame.com/&quot;&gt;Faster than Light&lt;/a&gt; again this weekend, this time for real. I bought it when it came out and I played it only in passing, but this weekend I played it a &lt;em&gt;ton&lt;/em&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/ftl_start.png&quot; /&gt;
&lt;figcaption&gt;Aaahh a new beginning in FTL. Will it be death once more&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I generally don’t like games where you have to restart after you die, I have a tendency to get really upset when things go badly. Yes I do rage quit when I play cs. But I really liked &lt;a href=&quot;http://www.ftlgame.com/&quot;&gt;FTL&lt;/a&gt; for some reason. It is frustrating sure, especially when you’re facing the final boss once more, and once &lt;em&gt;again&lt;/em&gt; you fail to beat him. I think I played 20 rounds from Friday to Sunday and yet I couldn’t beat him.&lt;/p&gt;
&lt;p&gt;Until now.&lt;/p&gt;
&lt;p&gt;I beat him using &lt;a href=&quot;http://ftl.wikia.com/wiki/Ships#Engi_Cruiser&quot;&gt;The Torus&lt;/a&gt;, with two scrap recovery augments and a drone recovery arm early on. Needless to say I went full blown drones and I had some nice shielding and cloaking going on, but it was still a hard fight. The feeling after was so satisfying! I practically jumped out of my chair in pure happiness and I messaged my friends and Veronica “I beat him! I beat him!”.&lt;/p&gt;
&lt;p&gt;Since then (since yesterday) I actually beat him again, but this time without the big yahoo reaction I was hoping for. But… I’m still plaing on easy mode… Do I dare to try normal next time?&lt;/p&gt;
</content></entry><entry><title>I, Robot</title><id>http://jonashietala.se/blog/2013/01/20/i_robot/index.html</id><updated>2023-10-01T08:35:05+00:00</updated><link href="https://www.jonashietala.se/blog/2013/01/20/i_robot" rel="alternate"/><published>2013-01-20T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Here are the results of the big robot construction course we had before christmas! The whole process went smooth and our group was amazing. The design and building of the robot went well even though in hindsight I would’ve changed a lot of stuff. The ending competition didn’t go quite as we had hoped, but we never did place much effort in it anyhow. In summary I’m very pleased with the result.&lt;/p&gt;
&lt;h1&gt;Competition&lt;/h1&gt;
&lt;p&gt;We had a competition with the other robots at the end. It didn’t matter how it went really, but as always it’s fun to do well. I couldn’t embed the youtube links, but here are our epic matches!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=EPU83cX80lY&quot;&gt;Game one&lt;/a&gt;. Went well, getting our hopes up!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=8vdG_2DkTNM&quot;&gt;Game two&lt;/a&gt;. Everything sucks. We accidentally touched the recalibrate button so the robot did not see the lines…&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=cSmzn0bQOu8&quot;&gt;Game three&lt;/a&gt;. Something is wrong with that curve I tell you! At least it felt better than loosing like the last one.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=YlRP1cb5iaw&quot;&gt;Game four (part 1)&lt;/a&gt; &lt;a href=&quot;http://www.youtube.com/watch?v=Jc7EPJa72wE&quot;&gt;Game four (part 2)&lt;/a&gt;. Retribution!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=ckLn-DY2yck&quot;&gt;Exhibition&lt;/a&gt;. Just a ploy game, with no rules. But they cheated anyway!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A bit upset about the second game… If that didn’t happen I’m sure we could’ve won the whole thing, maybe. But no matter!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/trap14/Robot_0017.JPG&quot; /&gt;
&lt;figcaption&gt;Do not &lt;strong&gt;ever&lt;/strong&gt; place the blue start button right next to the gray nuke button! Or was the nuke button blue?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Gallery&lt;/h1&gt;
&lt;p&gt;Here’s a bunch of nice photos of our robot.&lt;/p&gt;
&lt;figure class=&quot;gallery&quot;&gt;
&lt;a href=&quot;/images/trap14/Robot_0001.jpg&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0001.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0002.jpg&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0002.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0005.jpg&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0005.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0010.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0010.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0012.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0012.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0013.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0013.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0016.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0016.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0017.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0017.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0018.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0018.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0021.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0021.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0024.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0024.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0029.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0029.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0031.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0031.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0032.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0032.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0033.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0033.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0034.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0034.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0035.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0035.JPG&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/trap14/Robot_0037.JPG&quot;&gt;&lt;img src=&quot;/images/trap14/Robot_0037.JPG&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;</content></entry><entry><title>Fixing Problems</title><id>http://jonashietala.se/blog/2013/01/13/fixing_problems/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2013/01/13/fixing_problems" rel="alternate"/><published>2013-01-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Today I have fixed two large annoyances I’ve had!&lt;/p&gt;
&lt;h1&gt;I fixed &lt;a href=&quot;http://askubuntu.com/questions/117127/flash-video-appears-blue&quot;&gt;the blue people on youtube&lt;/a&gt; bug&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;http://i.stack.imgur.com/XvNff.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;I found a nice &lt;a href=&quot;http://askubuntu.com/questions/117127/flash-video-appears-blue&quot;&gt;thread&lt;/a&gt; with a great answer. I solved it by forcefully patching &lt;code&gt;libflashplayer.so&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;perl -pi.bak -e &apos;s/libvdpau/lixvdpau/g&apos; libflashplayer.so
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Worked perfectly!&lt;/p&gt;
&lt;h1&gt;I fixed the minecraft stuck in pause bug&lt;/h1&gt;
&lt;p&gt;This affects you if you’re using xmonad (or similar?) and java 1.7. The solution was simply to downgrade to java 1.6.&lt;/p&gt;
&lt;p&gt;Another problem I’ve had earlier was that minecraft tries to full screen over both of my screens instead of just one. The solution is to add this to your &lt;code&gt;xmonad.hs&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;haskell&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight haskell&quot;&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;main &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; xmonad defaultConfig {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator haskell&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;punctuation separator comma haskell&quot;&gt;,&lt;/span&gt; startupHook &lt;span class=&quot;keyword operator haskell&quot;&gt;=&lt;/span&gt; setWMName &lt;span class=&quot;string quoted double haskell&quot;&gt;&lt;span class=&quot;punctuation definition string begin haskell&quot;&gt;&amp;quot;&lt;/span&gt;LG3D&lt;span class=&quot;punctuation definition string end haskell&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword operator haskell&quot;&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Fixed my Todo Lists&lt;/h1&gt;
&lt;p&gt;Oh and I also added a lot of levels to my todo list, &lt;a href=&quot;http://www.aaronsw.com/weblog/productivity&quot;&gt;as suggested by this post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have now the levels&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Programming&lt;/li&gt;
&lt;li&gt;Writing&lt;/li&gt;
&lt;li&gt;Reading&lt;/li&gt;
&lt;li&gt;Watching&lt;/li&gt;
&lt;li&gt;Verro&lt;/li&gt;
&lt;li&gt;Misc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All so I can always have something to do pending on my different energy levels etc.&lt;/p&gt;
</content></entry><entry><title>A Vacation Filled with Obsession</title><id>http://jonashietala.se/blog/2013/01/07/a_vacation_filled_with_obsession/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2013/01/07/a_vacation_filled_with_obsession" rel="alternate"/><published>2013-01-07T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A nice thing about school are the nice long vacations. Directly after my last exam we went north to our dear home village Övertorneå and spent two weeks celebrating Christmas and New Years Eve. What did we do? I practiced some obsessive behavior with &lt;a href=&quot;http://boardgamegeek.com/boardgame/2651/power-grid&quot;&gt;Power Grid&lt;/a&gt; and &lt;a href=&quot;http://minecraft.net/&quot;&gt;Minecraft&lt;/a&gt; (and finishing up with some &lt;a href=&quot;http://worldoftanks.com/&quot;&gt;World of Tanks&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;It all began with &lt;a href=&quot;http://timharford.com/2010/07/why-we-still-love-board-games/&quot;&gt;an article&lt;/a&gt; and the discussion which followed on &lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;hacker news&lt;/a&gt;. Basically they discussed the pros and cons of different games and specifically noting the advantages of &lt;a href=&quot;http://en.wikipedia.org/wiki/German-style_board_game&quot;&gt;german style board games&lt;/a&gt; over classical board games like &lt;em&gt;Monopoly&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A summary from &lt;a href=&quot;http://en.wikipedia.org/wiki/German-style_board_game&quot;&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Themed games&lt;/li&gt;
&lt;li&gt;Games made for everyone&lt;/li&gt;
&lt;li&gt;No player elimination&lt;/li&gt;
&lt;li&gt;Game ‘mechanics’&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A note from &lt;em&gt;simonw&lt;/em&gt; about Monopoly which I can relate to.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Couldn’t agree more. German-style games make Monopoly etc look positively archaic. Two great starter games are Settlers of Catan and Carcassonne. I’m a big fan of Ticket to Ride as well.&lt;/p&gt;
&lt;p&gt;There are a couple of things that make these games so good. Firstly, they’re extremely well balanced - unlike Monopoly, it’s rare for one player to pull ahead to the point that it’s impossible for anyone else to catch up with them.&lt;/p&gt;
&lt;p&gt;Secondly, they tend to come to an inevitable conclusion - a game of Settlers will virtually never last more than an hour and a half due to resources / space on the board depleting over time. I’ve had games of Monopoly last 6 hours or more, by which time everyone is fed up and wishes they’d never started playing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After some debating I figured I’d order &lt;em&gt;Power Grid&lt;/em&gt; as it got really good reviews, both from the discussion thread and various reviews.&lt;/p&gt;
&lt;p&gt;And boy was it worth a buy!&lt;/p&gt;
&lt;p&gt;The first day I played maybe two games with my little brother, like me he’s very into games and we positively loved it. When my uncle (he loves board games as well) and cousin arrived we played a bit, and then some more. In total we played at least 20 times in 12 days, with a maximum of 4 times one day. The game takes 1,5 - 2 hours and is very mentally taxing so I consider that a &lt;em&gt;lot&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://cf.geekdo-images.com/images/pic1375788_md.jpg&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;em&gt;Power Grid, an great strategy game&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I liked it so much that I ordered three of the expansions for it just after I left.&lt;/p&gt;
&lt;p&gt;Of course we didn’t &lt;em&gt;only&lt;/em&gt; play &lt;em&gt;Power Grid&lt;/em&gt; day out and day in. We also started a new world in minecraft which we played a bit on… Sometimes things are just so good you can’t get enough of it you know?&lt;/p&gt;
</content></entry><entry><title>2012 in Review</title><id>http://jonashietala.se/blog/2012/12/31/2012_in_review/index.html</id><updated>2026-04-27T15:24:35+00:00</updated><link href="https://www.jonashietala.se/blog/2012/12/31/2012_in_review" rel="alternate"/><published>2012-12-31T23:07:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Like the &lt;a href=&quot;/blog/2012/01/04/2011_in_review/&quot;&gt;last&lt;/a&gt; &lt;a href=&quot;/blog/2011/01/06/2010_in_review/&quot;&gt;two&lt;/a&gt; years I’m summarizing the year. At the end of the year like this it always feel like I didn’t accomplish much, but after the yearly summary it always feels better.&lt;/p&gt;
&lt;h1&gt;2012 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/MARC&quot;&gt;Designed a processor&lt;/a&gt; which fulfills the &lt;a href=&quot;http://corewar.co.uk/icws88.txt&quot;&gt;Core Wars 88 standard&lt;/a&gt;. Includes a redcode assembler.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Went through &lt;a href=&quot;http://www.stanford.edu/class/cs140/projects/pintos/pintos.html&quot;&gt;pintos&lt;/a&gt; in school and learned a lot about operating systems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Began a new website.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some Ruby in conjunction with &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned some &lt;a href=&quot;http://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; and wrote a &lt;a href=&quot;https://codeberg.org/treeman/rustbot&quot;&gt;small irc bot&lt;/a&gt; with it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Took an advanced mathematics course in &lt;em&gt;Linear Algebra&lt;/em&gt;, it was fun!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I was a mathematics mentor to the first years in &lt;em&gt;Discrete Math&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Won the “best CV” award from Ericsson during Linkdagarna.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/files/cv-2012.pdf&quot;&gt;Here’s the CV (in Swedish)&lt;/a&gt; and &lt;a href=&quot;/files/cv-2012.tex&quot;&gt;here’s the latex file&lt;/a&gt; that produced it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Got top 3 in &lt;a href=&quot;https://www.ida.liu.se/projects/impa/new/&quot;&gt;IMPA&lt;/a&gt;, I did participate three turns out of five.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Participated in prog-SM and won a t-shirt! (Or three…)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Solved a lot of problems on &lt;a href=&quot;http://uva.onlinejudge.org/&quot;&gt;UVa&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Migrated all my private projects from &lt;a href=&quot;https://github.com/&quot;&gt;github&lt;/a&gt; to &lt;a href=&quot;https://bitbucket.org/&quot;&gt;bitbucket&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote a lot of C.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some C++.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrote some Perl.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Made a robot.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read one programming book - &lt;a href=&quot;http://en.wikipedia.org/wiki/The_C_Programming_Language&quot;&gt;The C Programming Language&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2012 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Me and Veronica had a good year.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Achieved 5-kup in Taekwon-do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2012/12/31/2012_read_books/&quot;&gt;Read 20 books&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a lot of manga. &lt;em&gt;Battle Royale&lt;/em&gt; was the highlight of the year I think.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read some manwha. Possibly better than manga??&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Tower of God&lt;/em&gt; (my favourite manga/manwha atm)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Magician&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The Breaker New Waves&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Noblesse&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Discovered &lt;a href=&quot;http://boardgamegeek.com/boardgame/2651/power-grid&quot;&gt;Power Grid&lt;/a&gt;, a &lt;a href=&quot;http://en.wikipedia.org/wiki/German-style_board_game&quot;&gt;German Style Boardgame&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2012 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Did not write enough code.&lt;/li&gt;
&lt;li&gt;Did not participate in &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Did not write a new game.&lt;/li&gt;
&lt;li&gt;I have a mechanic course behind me…&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2013&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Take care of Veronica.&lt;/li&gt;
&lt;li&gt;Complete a hardware project&lt;/li&gt;
&lt;li&gt;Try out some yoga.&lt;/li&gt;
&lt;li&gt;Learn about compilers.&lt;/li&gt;
&lt;li&gt;Take some fun courses.&lt;/li&gt;
&lt;li&gt;Achieve kup 3 in Taekwon-do.&lt;/li&gt;
&lt;li&gt;Develop this site a bit.&lt;/li&gt;
&lt;li&gt;Bigger and better blog posts.&lt;/li&gt;
&lt;li&gt;Work hard(er?) in school.&lt;/li&gt;
&lt;li&gt;Code more.&lt;/li&gt;
&lt;li&gt;Read more books.&lt;/li&gt;
&lt;li&gt;Fix the Failures of 2012.&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>2012 Read Books</title><id>http://jonashietala.se/blog/2012/12/31/2012_read_books/index.html</id><updated>2023-10-01T13:17:34+00:00</updated><link href="https://www.jonashietala.se/blog/2012/12/31/2012_read_books" rel="alternate"/><published>2012-12-31T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I read a post, sadly lost the link, where the author had recorded all books she had read during the year and I thought it’d be pretty fun to do. So here goes, in a mostly ordered list.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Art of Learning&lt;/strong&gt; - &lt;em&gt;Josh Waitzkin&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Världens Whiskey&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;More of a reference book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Linear Algebra Done Right&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Course book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Linear Algebra Done Wrong&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Course book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Effective Prototyping for Software Makers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Course book, selected chapters.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Över Näktergalens Golv&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;På en kudde av gräs&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Optimeringslära&lt;/strong&gt; - &lt;em&gt;Kaj Holmberg&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Course book, great both as a learning tool and reference book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dune&lt;/strong&gt; - &lt;em&gt;Frank Herbert&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A truly great book, the sci-fi world is amazing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Under lysande måne&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fit Forever&lt;/strong&gt; - &lt;em&gt;Dolph Lundgren&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Book of Cain&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dune Messiah&lt;/strong&gt; - &lt;em&gt;Frank Herbert&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Not quite like the first book, but still brilliant.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lärjungen&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The C programming Language&lt;/strong&gt; - &lt;em&gt;Kernighan and Ritchie&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Did not do all exercises, really good book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Software Engineering&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Course book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Operating System Concepts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Course book. Pretty good, although a bit wordy at times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Linear Systems and Signals&lt;/strong&gt; - &lt;em&gt;B. P. Lathi&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Course book. Quite good.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;XO&lt;/strong&gt; - &lt;em&gt;Jeffery Deaver&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Definite Book of Body Language&lt;/strong&gt; - &lt;em&gt;Allan &amp;amp; Barbara Pease&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Very informative and also pretty funny.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All in all, I did not read that many books this year. I did start on a few which I never finished for various reasons.&lt;/p&gt;
</content></entry><entry><title>Understanding the Computer</title><id>http://jonashietala.se/blog/2012/12/15/understanding_the_computer_bottom_up/index.html</id><updated>2026-04-27T11:09:46+00:00</updated><link href="https://www.jonashietala.se/blog/2012/12/15/understanding_the_computer_bottom_up" rel="alternate"/><published>2012-12-15T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;When I discovered programming it felt like a whole new world opened up for me with endless possibilities. It granted unlimited power and I could create virtually anything and it explained so much to me - how did a program work? How could you make a game or a website? But there was a big question without a good answer lurking in the background. I understood how you made the computer to do something and I understood the concept of electronics on a very crude level, but how did you ever go from a current to a full fledged game?&lt;/p&gt;
&lt;p&gt;After 2,5 years in University I finally feel I can understand &lt;em&gt;a bit&lt;/em&gt; of that. This is a simplified view of my journey so far.&lt;/p&gt;
&lt;h1&gt;Basic Electronics&lt;/h1&gt;
&lt;p&gt;We had a basic electronics course, although I must admit I never really got a good understanding of it and I haven’t used it enough to be comfortable with it. But I have at least a basic idea of how basic digital components can be realized.&lt;/p&gt;
&lt;h1&gt;Basic digital components&lt;/h1&gt;
&lt;p&gt;We only had one introductory course here as well. I didn’t like it at all at the time, I found it a bit dumb. Why care about the theory behind digital logic so much? Who cares?&lt;/p&gt;
&lt;p&gt;Well, it’s impossible to build something bigger without the building blocks and it’s hard to build a computer without basic combinatorical networks. Still didn’t like it though.&lt;/p&gt;
&lt;h1&gt;Larger digital components&lt;/h1&gt;
&lt;p&gt;This was the first hardware based course (we had several) I liked. Our mission was to build a digital clock or something. Turns out it’s really fun to build things! We extended the clock to be a counter, up or down, and we built other simple things. Life was good and the world of computers started unlocking a little, from the hardware point of view this time.&lt;/p&gt;
&lt;h1&gt;A processor&lt;/h1&gt;
&lt;p&gt;I’m not sure how it happened but the next step after playing with the smaller digital components was to play with a real CPU - motorola’s 68k family. This was also my first insight into assembly, it’s something I always wanted to know. Turns out it wasn’t all that different from regular programming, except that you’re dealing with much more detail. We used the processor to communicate with our familiar digital hardware, we made a 1D ping-pong with diodes and a simple “sinking ship” game and a lot of small assignments. We ported (parts of) Forth to it!&lt;/p&gt;
&lt;p&gt;After that we had a construction course, we could make a digital &lt;em&gt;thing&lt;/em&gt;! Maybe a processor, hurr? &lt;a href=&quot;https://codeberg.org/treeman/MARC/&quot;&gt;So we did&lt;/a&gt;. We made a microprogrammed processor, simulated on an FPGA, which ran redcode. I even wrote an assembler for it!&lt;/p&gt;
&lt;h1&gt;Compiler&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;I’m waiting eagerly for our compiler course to start in ~10 months.&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;Operating system&lt;/h1&gt;
&lt;p&gt;We had a super fun course about operating systems and we did some work in &lt;a href=&quot;http://www.stanford.edu/class/cs140/projects/pintos/pintos_1.html&quot;&gt;pintos&lt;/a&gt;, an OS where you’re supposed to improve and implement parts of it. It was perhaps the best course I’ve had yet and I learnt a &lt;em&gt;ton&lt;/em&gt;. Threading, scheduling, system calls, security, file systems, launching programs, etc…&lt;/p&gt;
&lt;p&gt;After pintos it feels like I understand what a OS does and how it communicates with hardware and programs.&lt;/p&gt;
&lt;h1&gt;A program&lt;/h1&gt;
&lt;p&gt;Ah, we’ve come a whole circle. I’m still writing programs, that’s practically all I’m doing, but now it feels like I have a better grasp of what it takes to run it.&lt;/p&gt;
&lt;p&gt;There are still things I’d like to do more of. More games, more assembly code, more hardware controlling stuff, using my &lt;a href=&quot;/blog/2012/12/14/early_christmas_present/&quot;&gt;newly gotten&lt;/a&gt; &lt;a href=&quot;http://www.raspberrypi.org/&quot;&gt;raspberry pi&lt;/a&gt; perhaps?, and I definately want to make my own programming language sometime.&lt;/p&gt;
</content></entry><entry><title>Early Christmas Present</title><id>http://jonashietala.se/blog/2012/12/14/early_christmas_present/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/12/14/early_christmas_present" rel="alternate"/><published>2012-12-14T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;School is almost over and it’s almost time to travel back up to Övertorneå. This year me and Veronica opened our Christmas presents a bit early - we’re impatient like that.&lt;/p&gt;
&lt;p&gt;I got one of the best presents yet I think! A &lt;a href=&quot;http://www.raspberrypi.org/&quot;&gt;Raspberry Pi&lt;/a&gt;!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/christmas12.jpg&quot; /&gt;
&lt;figcaption&gt;Just look at this bad boy!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;She got some crochet (virkning?) stuff from me, but she seemed content with that little. Now what shall I do with mine? I’m thinking of fetching a small screen for it and… and… Do something fun with it?&lt;/p&gt;
</content></entry><entry><title>Monaco What&apos;s Yours is Mine</title><id>http://jonashietala.se/blog/2012/12/12/monaco_whats_yours_is_mine/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/12/12/monaco_whats_yours_is_mine" rel="alternate"/><published>2012-12-12T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been waiting for soon to be three years for &lt;a href=&quot;http://www.monacoismine.com/&quot;&gt;Monaco What’s Yours is Mine&lt;/a&gt;, and today I was granted an early christmas present - I was given a beta key! w00p!!&lt;/p&gt;
&lt;p&gt;I was planning on studying and sending some emails to some companies… But who knows what I’ll end up doing?&lt;/p&gt;
&lt;p&gt;Tomorrow is preorder release, yes I’m going to buy a 4-pack directly, and they will also stream etc. But for new enjoy the 10 month old gameplay video!&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=NtpLP4_losA&quot;&gt;https://www.youtube.com/watch?v=NtpLP4_losA&lt;/a&gt;</content></entry><entry><title>5 Kup</title><id>http://jonashietala.se/blog/2012/12/02/5_kup/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/12/02/5_kup" rel="alternate"/><published>2012-12-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;After a season with very bad attendence, I blame school and lack of motivation, I still went to grading. I slept well but I was super stressed all weekend so I had to constantly run to the bathroom and I couldn’t eat lunch or breakfast properly, and I don’t usually get nervous…&lt;/p&gt;
&lt;p&gt;Anyways the grading went well, the kids where absolutely great! They trained 6+ hours on Saturday and 4-5 hours on Sunday and they never complained or made any trouble whatsoever. I’m so proud!&lt;/p&gt;
&lt;p&gt;My grading went well, I was worried about some jumping kicks… But I didn’t need to do them! The sparring went okay, but nothing really admirable, I guess I need to show up to more trainings. The breaking didn’t pose any problem and the patterns went well, although I got super tired by the end.&lt;/p&gt;
&lt;p&gt;At the end I succeeded in leveling up, next one is a blue belt! I really, really need to work on my kicks though.&lt;/p&gt;
</content></entry><entry><title>Dbot</title><id>http://jonashietala.se/blog/2012/11/13/dbot/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/11/13/dbot" rel="alternate"/><published>2012-11-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I made a small irc bot in 294 characters in code-golfing language #1: Perl.&lt;/p&gt;
&lt;h1&gt;Usage&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;perl Dbot&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;Commands&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.name&lt;/code&gt; - Echo the bots name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.hello&lt;/code&gt; - Output “hello world!”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.src&lt;/code&gt; - Dump the source code&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Code&lt;/h1&gt;
&lt;div class=&quot;code-wrapper wide&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;perl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight perl&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control perl&quot;&gt;use&lt;/span&gt; IO::Socket;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;s&lt;/span&gt;=IO::Socket::INET&lt;span class=&quot;keyword operator comparison perl&quot;&gt;-&amp;gt;&lt;/span&gt;new(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;158.38.8.251:6667&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);sub o{&lt;span class=&quot;support function perl&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;s&lt;/span&gt; &lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;variable other predefined perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;_&lt;/span&gt;[0]&lt;span class=&quot;constant character escape perl&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;NICK &lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;USER b * * :b&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;span class=&quot;keyword control perl&quot;&gt;while&lt;/span&gt;(&amp;lt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;s&lt;/span&gt;&amp;gt;){o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;PONG&lt;span class=&quot;variable other subpattern perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;string regexp find perl&quot;&gt;&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;^PING(.*)$&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;;o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;JOIN #&lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;string regexp find perl&quot;&gt;&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;004&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;;&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;((&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p&lt;/span&gt;,&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt;)=&lt;span class=&quot;string regexp find perl&quot;&gt;&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;(P.+)\.(.*).&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;){o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p$h&lt;/span&gt; world!&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt;=~&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;h&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;o(&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p&lt;/span&gt;.&lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;)&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt;=~&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;(&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt;=~&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;s&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;){&lt;span class=&quot;support function perl&quot;&gt;open&lt;/span&gt; F,&lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;;o(&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p&lt;/span&gt;.&lt;span class=&quot;keyword control perl&quot;&gt;do&lt;/span&gt;{&lt;span class=&quot;storage modifier perl&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;variable other predefined perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;/&lt;/span&gt;=&amp;lt;F&amp;gt;})}}}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well uh let’s try that again, without minimize shall we?&lt;/p&gt;
&lt;div class=&quot;code-wrapper&quot;&gt;&lt;div class=&quot;descr&quot; data-descr=&quot;perl&quot;&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;highlight perl&quot;&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;keyword control perl&quot;&gt;use&lt;/span&gt; IO::Socket;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta comment full-line perl&quot;&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Connect to one server of irc.quakenet.org
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;s&lt;/span&gt; = IO::Socket::INET&lt;span class=&quot;keyword operator comparison perl&quot;&gt;-&amp;gt;&lt;/span&gt;new(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;158.38.8.251:6667&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta comment full-line perl&quot;&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; o(&amp;quot;txt&amp;quot;) writes &amp;quot;txt\n&amp;quot; to the server
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;meta function perl&quot;&gt;&lt;span class=&quot;storage type sub perl&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;entity name function perl&quot;&gt;o&lt;/span&gt;&lt;/span&gt;{ &lt;span class=&quot;support function perl&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;s&lt;/span&gt; &lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;variable other predefined perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;_&lt;/span&gt;[0]&lt;span class=&quot;constant character escape perl&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta comment full-line perl&quot;&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Register our nickname, same as file name
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;NICK &lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta comment full-line perl&quot;&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Register username, necessary stuff :&amp;lt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;USER b * * :b&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta comment full-line perl&quot;&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Never quit!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword control perl&quot;&gt;while&lt;/span&gt;(&amp;lt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;s&lt;/span&gt;&amp;gt;) {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Play a bit of ping-pong
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;PONG&lt;span class=&quot;variable other subpattern perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;1&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;string regexp find perl&quot;&gt;&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;^PING(.*)$&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Join when ping-pong has completed
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;JOIN #&lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;string regexp find perl&quot;&gt;&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;004&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Parse a message our channel with message &amp;quot;.&amp;lt;cmd&amp;gt;&amp;quot;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; so example:
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; :&amp;lt;user-info&amp;gt; PRIVMSG #&amp;lt;channel&amp;gt; :.&amp;lt;cmd&amp;gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; (P.+) Match &amp;#39;PRIVMSG #&amp;lt;channel&amp;gt; :&amp;#39;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; \. Cmd prefix
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; (.*) Cmd
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; . Trailing \r
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;((&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p&lt;/span&gt;,&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt;) = &lt;span class=&quot;string regexp find perl&quot;&gt;&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;(P.+)\.(.*).&lt;span class=&quot;punctuation definition string perl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;) {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; .hello Echo hello world! Unless an abuser appears!
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;o(&lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p$h&lt;/span&gt; world!&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt; =~ &lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;h&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; .name Echo name of bot
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;o(&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p&lt;/span&gt;.&lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;) &lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt; =~ &lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;n&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; .src Output whole source code
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;keyword control perl&quot;&gt;if&lt;/span&gt;(&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;h&lt;/span&gt; =~ &lt;span class=&quot;string quoted double perl&quot;&gt;&lt;span class=&quot;punctuation definition string begin perl&quot;&gt;&amp;quot;&lt;/span&gt;s&lt;span class=&quot;punctuation definition string end perl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) {
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Open running script file handler
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;support function perl&quot;&gt;open&lt;/span&gt; F,&lt;span class=&quot;variable other predefined program-name perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;0&lt;/span&gt;;
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; Echo contents of running script
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;comment line number-sign perl&quot;&gt;&lt;span class=&quot;punctuation definition comment perl&quot;&gt;#&lt;/span&gt; file slurping
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;/span&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;o(&lt;span class=&quot;variable other readwrite global perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;p&lt;/span&gt; . &lt;span class=&quot;keyword control perl&quot;&gt;do&lt;/span&gt;{ &lt;span class=&quot;storage modifier perl&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;variable other predefined perl&quot;&gt;&lt;span class=&quot;punctuation definition variable perl&quot;&gt;$&lt;/span&gt;/&lt;/span&gt; = &amp;lt;F&amp;gt; })
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;meta even-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;&lt;span class=&quot;meta leading-tabs&quot;&gt;&lt;span class=&quot;meta odd-tab&quot;&gt;    &lt;/span&gt;&lt;/span&gt;}
&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;}
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All hacky, but I had some fun with it.&lt;/p&gt;
</content></entry><entry><title>Good and Bad Programmers</title><id>http://jonashietala.se/blog/2012/11/08/good_and_bad_programmers/index.html</id><updated>2024-10-31T08:32:35+00:00</updated><link href="https://www.jonashietala.se/blog/2012/11/08/good_and_bad_programmers" rel="alternate"/><published>2012-11-08T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Every now and day blog posts about what it takes to be a good programmer or how you figure out if someone is a bad programmer arrives. There’s always talk about how you find the good programmers in interviews and the topic is always hot in schools and universities.&lt;/p&gt;
&lt;p&gt;Today I read the best comment so far about the topic by &lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;Hacker News&lt;/a&gt; regular edw519:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;My default response to any “good programmer, bad programmer” post:&lt;/p&gt;
&lt;p&gt;A smart accountant once told me that the answer to “How much money did you make?” is always, “Who wants to know?” If it’s an investor, the answer is “A lot.” If it’s a customer, the answer is “A little.” If it’s the IRS, the answer is “None.”&lt;/p&gt;
&lt;p&gt;Same thing here. The answer to “Who is a good programmer?” is always, “Who wants to know?”&lt;/p&gt;
&lt;p&gt;To a project manager, the programmer who hits every deadline (regardless of quality) is a good programmer.&lt;/p&gt;
&lt;p&gt;To a customer, the programmer who solves their problem quickest is a good programmer.&lt;/p&gt;
&lt;p&gt;To a business owner, the programmer who makes them the most money is a good programmer.&lt;/p&gt;
&lt;p&gt;To a PHB, the programmer who makes them look the best is a good programmer.&lt;/p&gt;
&lt;p&gt;To a journalist, the programmer who tells the best stories is a good programmer.&lt;/p&gt;
&lt;p&gt;To a junior programmer, the best mentor is the good programmer.&lt;/p&gt;
&lt;p&gt;To another programmer, the programmer they are most likely to want to go into battle with is a good programmer.&lt;/p&gt;
&lt;p&gt;To a blogger, the programmer who best fits the profile of the point he is trying to make is a good programmer.&lt;/p&gt;
&lt;/blockquote&gt;</content></entry><entry><title>Laying off Pintos</title><id>http://jonashietala.se/blog/2012/10/16/laying_off_pintos/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/10/16/laying_off_pintos" rel="alternate"/><published>2012-10-16T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Exam period is here which means all courses should be wrapping up and a week or so ago we finished up &lt;a href=&quot;/blog/2012/09/03/entering_pintos/&quot;&gt;our lab series&lt;/a&gt; about &lt;a href=&quot;http://www.stanford.edu/class/cs140/projects/pintos/pintos_1.html&quot;&gt;pintos&lt;/a&gt;. The labs were among the best I’ve had yet and I learned a ton. We didn’t follow the official instructions but we had our own assigmnets. Basically:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Implement some basic system calls.&lt;/li&gt;
&lt;li&gt;Reimplement &lt;code&gt;timer_sleep&lt;/code&gt; to not use busy waiting.&lt;/li&gt;
&lt;li&gt;Implement synchronization between processes, program arguments and securing the system calls.
Yes quite a bit bigger than the rest.&lt;/li&gt;
&lt;li&gt;Synchronize the file system.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All in all pretty darn fun. I was considering sharing the code publicly, but that might not be a too bright of an idea. I’ll keep it private for now.&lt;/p&gt;
</content></entry><entry><title>Moving private repositories to Bitbucket</title><id>http://jonashietala.se/blog/2012/10/10/moving_private_repositories_to_bitbucket/index.html</id><updated>2026-04-28T05:07:32+00:00</updated><link href="https://www.jonashietala.se/blog/2012/10/10/moving_private_repositories_to_bitbucket" rel="alternate"/><published>2012-10-10T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Long overdue, I recently moved my private repositories from &lt;a href=&quot;https://github.com/treeman&quot;&gt;Github&lt;/a&gt; to &lt;a href=&quot;https://bitbucket.org/&quot;&gt;Bitbucket&lt;/a&gt;. Github is great of course and they even gave me a free students account and I still host all my &lt;a href=&quot;https://github.com/treeman&quot;&gt;public repositories&lt;/a&gt; there. Still, Bitbucket has unlimited free private repositories for up to 5 users which is a much better pricing model. And Bitbucket is pretty awesome as well, they’re posting a lot on &lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;hacker news&lt;/a&gt;, my favourite place on the web. That’s where the &lt;a href=&quot;https://news.ycombinator.com/item?id=4631926&quot;&gt;final push&lt;/a&gt; came from anyway.&lt;/p&gt;
&lt;p&gt;The transition was as smooth as a… a sine wave…? Pretty damn smooth that is. Sign up took 30 seconds, copy paste my ssh key and redefine some remotes and I’m basically done. Decentralized source code management (git in this case) is pretty damn awesome.&lt;/p&gt;
</content></entry><entry><title>Eduroam for wicd in Linkoping&apos;s University</title><id>http://jonashietala.se/blog/2012/09/13/eduroam_for_wicd_in_linkopings_university/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/09/13/eduroam_for_wicd_in_linkopings_university" rel="alternate"/><published>2012-09-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So we have eduroam at our University and unsurprisingly wicd is not on their official support list but with some googling the wonderful &lt;a href=&quot;https://wiki.archlinux.org/index.php/Wicd#Making_eduroam_work_with_wicd&quot;&gt;Arch Wiki&lt;/a&gt; had the answer. Well, almost.&lt;/p&gt;
&lt;p&gt;Save the following as &lt;code&gt;/etc/wicd/encryption/templates/ttls-80211&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name = TTLS for Wireless
author = Alexander Clouter
version = 1
require anon_identity *Anonymous_Username identity *Identity password *Password
optional ca_cert *Path_to_CA_Cert
-----
ctrl_interface=/var/run/wpa_supplicant
network={
    ssid=&quot;$_ESSID&quot;
    scan_ssid=$_SCAN

    key_mgmt=WPA-EAP
    eap=TTLS

    ca_cert=&quot;$_CA_CERT&quot;

    phase2=&quot;auth=MSCHAPv2 auth=PAP&quot;

    anonymous_identity=&quot;$_ANON_IDENTITY&quot;
    identity=&quot;$_IDENTITY&quot;
    password=&quot;$_PASSWORD&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only difference from the wiki is the line &lt;code&gt;subject_match=&quot;$_CERT_SUBJECT&quot;&lt;/code&gt; is removed.&lt;/p&gt;
&lt;p&gt;In a terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /etc/wicd/encryption/templates
echo ttls-80211 &amp;gt;&amp;gt; active
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then open wicd (I use &lt;code&gt;wicd-curses&lt;/code&gt;) and choose &lt;code&gt;TTLS for Wireless&lt;/code&gt; under the security mode and enter your credentials &lt;a href=&quot;http://www.liu.se/insidan/it/natverk/tradlost-nat/korta-installningar?l=sv&quot;&gt;from this page&lt;/a&gt;. For the lazy people &lt;a href=&quot;http://www.liu.se/insidan/it/natverk/tradlost-nat/korta-installningar/1.198388/AddTrustExternalCARoot.crt&quot;&gt;download this&lt;/a&gt;, save it somewhere and specify the path to it as &lt;code&gt;Path to CA Cert&lt;/code&gt; then input your &lt;code&gt;&amp;lt;name&amp;gt;@liu.se&lt;/code&gt; or &lt;code&gt;&amp;lt;name&amp;gt;@student.liu.se&lt;/code&gt; and don’t forget &lt;a href=&quot;https://account.liu.se&quot;&gt;your password&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Done!&lt;/p&gt;
</content></entry><entry><title>Robot Project Start</title><id>http://jonashietala.se/blog/2012/09/05/robot_project_start/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/09/05/robot_project_start" rel="alternate"/><published>2012-09-05T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So it has begun, the long road until christmas when we’re supposed to have a working warrior robot. We’re gonna do battle with infrared lasers instead of axes but it might be fun anyway. Luckily for me I’m responsible for software and nothing harder than that! w00p!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/R_wars.jpg&quot; /&gt;
&lt;figcaption&gt;We could maybe cheat a little…&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Our group seem pretty good, all nice guys (so far!) and we have guys on the harder jobs - documentation responsibilities and project leader - so it &lt;em&gt;should&lt;/em&gt; go well. We’ll see!&lt;/p&gt;
</content></entry><entry><title>Entering Pintos</title><id>http://jonashietala.se/blog/2012/09/03/entering_pintos/index.html</id><updated>2026-04-27T11:09:34+00:00</updated><link href="https://www.jonashietala.se/blog/2012/09/03/entering_pintos" rel="alternate"/><published>2012-09-03T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;First week of school is over and it’s been full throttle from the start, in a good way. We’re having four courses and for once I like them all. We have an interesting math course, a useful course “Software Development in Theory” (boring but useful) and a big project course where we shall build a robot. That’ll be fun! But my favourite course so far has been the course about operating systems where we’re supposed to add functionality to &lt;a href=&quot;http://www.stanford.edu/class/cs140/projects/pintos/pintos_1.html&quot;&gt;pintos&lt;/a&gt;, a toy operating system from stanford.&lt;/p&gt;
&lt;p&gt;It’s one of the things I’ve been wanting to learn every since I first came in contact with programming; How does the connection hardware to software work? How does an operating system work? And how does a programming language work? After two years, with &lt;a href=&quot;https://codeberg.org/treeman/MARC&quot;&gt;implementing a processor&lt;/a&gt; last year as a high point, I think I can answer how hardware connect with software. I still need to implement my own language but for now I’m having fun with OS programming. Yesterday I implemented basic System Calls and next on the agenda is altering some thread stuff. I might make the code available when the course is over, and maybe even add even more stuff? Fun, Fun!&lt;/p&gt;
</content></entry><entry><title>It&apos;s Time for More School</title><id>http://jonashietala.se/blog/2012/08/27/its_time_for_more_school/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/08/27/its_time_for_more_school" rel="alternate"/><published>2012-08-27T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Today it’s finally starting again and it’s off with a flying start. We have 11 lectures this first week and an absolutely smacked schedule. If that wasn’t enough I also have a mentor time to prepare for and I need to start Taekwon-do again.&lt;/p&gt;
&lt;p&gt;On another note Ḯ’m currently plowing through ‘Liar Game’ manga which is pretty damn nice. It’s a psychological manga about various games where you’re supposed to lie and cheat your way to victory. Corny as it may sound it’s pretty good.&lt;/p&gt;
</content></entry><entry><title>Rising from the Dead, it&apos;s Ludum Dare</title><id>http://jonashietala.se/blog/2012/08/25/rising_from_the_dead_its_ludum_dare/index.html</id><updated>2023-10-01T13:15:24+00:00</updated><link href="https://www.jonashietala.se/blog/2012/08/25/rising_from_the_dead_its_ludum_dare" rel="alternate"/><published>2012-08-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been a long time gone, been busy with school then having summer vacation and generally not making games or blogging. But I have revived! I scrambled to push my new website live because today it’s Ludum Dare time! The theme is “Evolution” and it’s the 24th time for Ludum Dare and my 4th time entering.&lt;/p&gt;
&lt;p&gt;Of course, as usual with my Ludum Dare entries I’m totally unprepared. I haven’t used any of the tools I’m going to use in over half a year or something.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/ld24_full_desktop.jpg&quot; /&gt;
&lt;figcaption&gt;But I did clear my desk! And an inspirational cactus friend!&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Ugly and Slow Progress</title><id>http://jonashietala.se/blog/2012/08/25/ugly_and_slow_progress/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/08/25/ugly_and_slow_progress" rel="alternate"/><published>2012-08-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Ludum Dare is coming along… Slowly. The rust on me is probably so brown it’s nearly black. But I have an idea and it might be good, all I need to do is execute it. Right?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/2012-08-25-145327.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;em&gt;Programmer graphics coming to take you away!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Anyway it’s going to be a risk-like game with a twist: you can change all the rules and victory conditions. I played a pretty cool card game where changing the rules was the core of the game, pretty neat idea actually. As for the theme I wanted to do something with robots taking over the world - it’s only the next logic evolution of computers anyway.&lt;/p&gt;
&lt;p&gt;Not sure if the game is going to be anything to celebrate over, but I’m having fun at least. Except for getting annoyed about C++ missing all my favourite features from other languages… But in time I’ll be in love with it anyway.&lt;/p&gt;
</content></entry><entry><title>Up like a Sun, Down like a Pancake</title><id>http://jonashietala.se/blog/2012/08/25/up_like_a_sun_down_like_a_pancake/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/08/25/up_like_a_sun_down_like_a_pancake" rel="alternate"/><published>2012-08-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I was looking forward to this weekend, for Ludum Dare and for me to finally make a game again. But it just don’t feel right to me. I’m not prepared, I feel a little bit stressed and I don’t really have faith in my game so I’m gonna step down this one as well. But it’s fine, Ludum Dare is supposed to be fun and challenging with an emphasis on fun but as it is now I just don’t really feel it.&lt;/p&gt;
&lt;p&gt;Next time I will come more prepared, that’s a must! I think I need to do some html5 or pygame for the next time. Fast prototyping should mean more than writing a lot of boilerplate code and the boiler will make a damn stew if you’re rusty.&lt;/p&gt;
</content></entry><entry><title>Beginning Programming</title><id>http://jonashietala.se/blog/2012/03/18/beginning_programming/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/03/18/beginning_programming" rel="alternate"/><published>2012-03-18T15:26:46+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I read a wonderful post, &lt;a href=&quot;http://allfuzzy.tumblr.com/post/19464639511/3-things-i-hate-about-beginner-programming-books&quot;&gt;3 Things I hate about “beginner” programming books&lt;/a&gt;, which I couldn’t agree more with. Basically he has these points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Too long&lt;/li&gt;
&lt;li&gt;Too many examples like “Hello World!”&lt;/li&gt;
&lt;li&gt;No answers to exercises.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nr 1 is a pretty curious one. Even though I think a book is good, I often end up only completing 75-85% of it before going on with my own projects or with something else. Also the best books are often shorter than your average 700+ pages brick. &lt;a href=&quot;http://www.modernperlbooks.com/&quot; title=&quot;Modern Perl book&quot;&gt;Modern Perl&lt;/a&gt;, &lt;a href=&quot;http://pragprog.com/the-pragmatic-programmer&quot; title=&quot;The Pragmatic Programmer&quot;&gt;The Pragmatic Programmer&lt;/a&gt; and &lt;a href=&quot;http://aristeia.com/books.html&quot; title=&quot;Scott Meyers books Effective C++, More Effective C++&quot;&gt;Effective C++&lt;/a&gt; are all short but really good.&lt;/p&gt;
&lt;p&gt;I always hate, really hate, when I can’t find an answer to an exercise in a book. Often I’m unsure or I frankly don’t know how to solve something, even after reading the text and examples, and I also think I learn best by copying. This may sound strange to you but I swear it’s true. When I made my first game I copied from a tutorial and after I changed and wrote something new. This is also the same when doing math, first I want too see examples and how to actually solve something then I copy that and then I go “hmm what does this do, what will happen here”.&lt;/p&gt;
&lt;p&gt;The small constructed examples you always see, “this Vehicle is a class and the Firetruck inherits Vehicle”, are no use at all I’d say. Is that how you solve a problem? Is that how you program? Not really. Almost all examples are contrived and not useful at all, especially for beginners. I never thought classes where good before I copied a solution to some problem I had. Wonderful!&lt;/p&gt;
&lt;p&gt;This is what I’d do if I would write a “beginner” programming book:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I would use the whole book to construct a game. I would begin with simply drawing a shape, or an image, on the screen. Then I would make it move and at the end of the book I would have all the necessary code for a complete and functional game.&lt;/li&gt;
&lt;li&gt;I would provide &lt;em&gt;all&lt;/em&gt; the code inside the book. Of course I could provide it online but the act of actually typing in something yourself is very valuable.&lt;/li&gt;
&lt;li&gt;It should be fun and easy-going. I wouldn’t focus on every little detail but instead on the big picture and my goal would be to get the reader hooked on programming.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s it! Learning programming is hard, but it’s also very satisfying. My summer project will be to teach my little brother to program, we’ll see how that’ll go.&lt;/p&gt;
</content></entry><entry><title>Changes</title><id>http://jonashietala.se/blog/2012/03/04/changes/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/03/04/changes" rel="alternate"/><published>2012-03-04T20:21:17+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A lot has been going on lately and it feels like I’m being swamped. I can’t complain too much but there are things I’d like to change after the exam period this week.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Program more!&lt;br /&gt;
I have seriously done &lt;em&gt;nothing&lt;/em&gt; since christmas or someting. I need to finish:&lt;/li&gt;
&lt;li&gt;Ada project for school. Can’t believe I still haven’t done it.&lt;/li&gt;
&lt;li&gt;New web page. Need to track down a good perl hosting service and actually finish the site.&lt;/li&gt;
&lt;li&gt;Game for my little brother to create graphics and tweak some code in, I want to teach him to code during the summer! That’s a good healthy challange for me.&lt;/li&gt;
&lt;li&gt;Ludum Dare 23 in April, yay!&lt;/li&gt;
&lt;li&gt;Serious Taekwon-do training.&lt;/li&gt;
&lt;li&gt;Don’t fall behind too much in school.  This time I’m hurrying like mad to catch up before exam and I’m actually worried. This shouldn’t happen! I didn’t even go to &lt;em&gt;a single&lt;/em&gt; lesson this time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Just wanted to get that out there.&lt;/p&gt;
</content></entry><entry><title>Favourite Programming Language</title><id>http://jonashietala.se/blog/2012/02/24/favourite_programming_language/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/02/24/favourite_programming_language" rel="alternate"/><published>2012-02-24T20:05:47+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;All the programmers love to promote their favourite language, or to hate on others. Now I read a post which claimes &lt;a href=&quot;http://blaag.haard.se/Your-favourite-programming-language-is-not-good-enough/&quot;&gt;my favourite language is not good enough&lt;/a&gt;! But he’s correct of course, there is no one language to rule them all. You should always choose the mest language for the job, be it C or Ruby, but most don’t learn enough of them. Maybe he’s right, maybe we’re all just lazy?&lt;/p&gt;
&lt;p&gt;Whatever the reason I certainly have a favourite language, or rather a few. If I would have to name one I would probably say Perl, just because I’ve had the most fun with it! I do enjoy C++ and as I’ve made most of my precious games in it that’s a good candidate. Haskell is absolutely awesome and so is Lisp. There I’ve listed 4 favourites! But of course I don’t care about that really, I tend to fall in love with most of the languages I use.&lt;/p&gt;
&lt;p&gt;Well I don’t particulary like Ada… But I do admit it has some nice features, and the error messages are great! But how about Java then? I’ve been joking around a lot with it but to be honest I don’t really hate it. Sure there are better alternatives but there are good points. The JVM, the libraries and the simplicity of it appeals to me. Maybe it’s not simple but I’m used to the thinking.&lt;/p&gt;
&lt;p&gt;To echo &lt;a href=&quot;http://blaag.haard.se/Your-favourite-programming-language-is-not-good-enough/&quot;&gt;his&lt;/a&gt; suggestion: learn new languages. I’ll add that don’t just learn them: use them for something real and learn to love them! And don’t just learn similar languages (from C++ to Java isn’t worth it) but try to switch it up a bit (try C++ to Haskell). You’ll find you’ll be a better programmer when the dust settles, and you can actually choose a language gwith the strengths for a particular prolem.&lt;/p&gt;
&lt;p&gt;End rant.&lt;/p&gt;
</content></entry><entry><title>Motivation is Valuable</title><id>http://jonashietala.se/blog/2012/02/24/motivation_is_valuable/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/02/24/motivation_is_valuable" rel="alternate"/><published>2012-02-24T08:56:05+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s funny how motivation can play such a huge role with my productivity. I’m currently having two math courses; one mandatory about analysis in multiple variables and vector analysis and one voluntary about advanced linear algebra. I don’t like the analysis course, didn’t like the previous ones and I don’t like this one.I don’t fall asleep on lectures ever and I always try my best to listen but this one is pretty horrible. Not sure if the teacher or the content is to blame?&lt;/p&gt;
&lt;p&gt;On the other hand the linear algebra course is fun and intriguing. Every lecture I’m always surprised when it ends “already 2 hours?”. This is so funny because I’m not really convinced why this is happening, are the courses or the teachers that different? Sure that’s probably true, but mostly I think it’s my motivation that’s hurting me.&lt;/p&gt;
&lt;p&gt;“Linear algebra seems fun! It’s hard but I &lt;em&gt;will&lt;/em&gt; manage it.” vs “Pah analysis again. Damn the first lecture was boring, this course is boring”. I do like linear algebra more and I think it’ll be much more useful for me in my programming career but analysis isn’t so bad, not this degree. I think my motivation blow ups my it into bigger proportions than it really is.&lt;/p&gt;
&lt;p&gt;It’s pretty bad, we have exam in two weeks and I have literary done nothing in the analysis course… Now I need to study hard if I want to complete it but the lack of motivation is just sooo hard to overcome. Sometimes I think I don’t have the mentality to be a good student. Many of my class mates are in school the whole day, every day, while I try to be in school as little as possible.&lt;/p&gt;
</content></entry><entry><title>Doing Stuff</title><id>http://jonashietala.se/blog/2012/02/12/doing_stuff/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/02/12/doing_stuff" rel="alternate"/><published>2012-02-12T13:34:39+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The school and my life is trotting along. I’m handling the extra course fine, but instead I’ve left the standard math course behind a bit. Actually more than a bit but hopefully I’ll correct things later.&lt;/p&gt;
&lt;p&gt;No my life is going along just fine, it almost feels like my life is runing ahead and leaving me behind. What have I done lately? School work I guess? Can’t think of anything else the last month to be completely honest, which is pretty far from optimal. I set out this school year with the goal of programming a lot more, but so far that has been pretty dead. Sure I made a lot of progress on the new site during the christmas break but since school started I have done nothing, &lt;em&gt;nothing&lt;/em&gt;! So sad.&lt;/p&gt;
&lt;p&gt;Yesterday I did something else though. I went and bought a bunch of stuff. I bought a birthday present for Veronica which I’m very happy with, and I bought some rubber bands for training the oblique muscles among others. I tried but I couldn’t find a protective condom for my new phone, yes I have a new phone! A white, shining, wonderful &lt;a href=&quot;http://www.techradar.com/reviews/phones/mobile-phones/samsung-galaxy-s2-930907/review&quot;&gt;Samsung Galaxy S2&lt;/a&gt; which is blowing my mind. I can now surf, watch starcraft and read manga in bed, in the bathroom and in school! Yay! And umm… New boxers.&lt;/p&gt;
&lt;p&gt;Apart from all that I also hung up Veronica’s two paintings and a white shelf I’ve been meaning to a while. I realized I had no idea whatsoever how to hang up a painting! I bought a big box with screws and stuff but there where only one of them I knew how to use. Now I know how to hang up a painting like the leaning tower of Pisa!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;http://4.bp.blogspot.com/-LqiqWRrdHX4/TX9XHvYIooI/AAAAAAAABqM/a2FTabGMO5Y/s400/leaning-tower-of-pisa.jpg&quot; title=&quot;Leaning tower of Pisa&quot; /&gt;
&lt;figcaption&gt;You call that leaning? You should check out my paintings!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I finally got them sort-of straight, but it took a while.&lt;/p&gt;
&lt;p&gt;You know your life is running fast if you’re savouring hanging up paintings. But now I will do something about that: I will go to Taekwon-do practice and later maybe going to the children’s practice, yay!&lt;/p&gt;
</content></entry><entry><title>A Simple Thought</title><id>http://jonashietala.se/blog/2012/02/02/a_simple_thought/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/02/02/a_simple_thought" rel="alternate"/><published>2012-02-02T13:14:35+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;a href=&quot;/blog/2012/01/29/speeding_ahead&quot;&gt;I wrote&lt;/a&gt; that we where doing some microprogramming, making the processor work etc. We had a lab about that yesterday and I was very, very nervous. The preparations weren’t that hard, but they where very bothersome. Converting the instructions to binary/hex by hand is never nice. Turns out the lab was very easy! You also had the option to prepare everything before on their simulator, which dumb be didn’t do.&lt;/p&gt;
&lt;p&gt;When I thought about how to describe what microprogramming is I was going to write that it’s what makes a processor work. This sounds a bit off though, couldn’t you do the same with physical hardware instead of another programming step inside the processor? Well turns out that’s what RISC is all about. Sometimes the qualms you have when facing something new are completely justified.&lt;/p&gt;
</content></entry><entry><title>Speeding Ahead</title><id>http://jonashietala.se/blog/2012/01/29/speeding_ahead/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/01/29/speeding_ahead" rel="alternate"/><published>2012-01-29T20:44:15+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Life is slowly settling down over here. School has started with some pretty interesting stuff this year. Firstly we have a math analysis course in multiple variables which is ok. I’m not a fan of the previous analysis courses but maybe this will be a bit different. We’re contining with computer hardware, microprogramming and such, and I enjoy it a little.&lt;/p&gt;
&lt;p&gt;When I started programming the big question was how did the code I typed into my editor become something the processor could understand? I’ve got a good feeling for different programming languages, and now including the assembly for 86k processors. Now the basic hardware, from logical gates to ackumulators, and code are being connected together which feels very nice indeed. I still like to construct and make stuff in a more high level way though.&lt;/p&gt;
&lt;p&gt;We’re also having a new course, it’s been totally remade since last year, about software prototyping. I’m quite used to prototyping with my games but as expected a university course about the subject is a bit more structured and dare I say more boring? The course book, &lt;a href=&quot;http://www.powells.com/biblio?isbn=9780120885688&quot;&gt;Effective Prototyping for Software Makers&lt;/a&gt;, is pretty good as it explains the design process in a formal, but not mindnumbingly boring, way. I need to investigate more but I’ll definitely use some of the ideas.&lt;/p&gt;
&lt;p&gt;The last course for now is the advanced course in linear algebra which me and a friend chose. Linear algebra was probably the hardest math course we’ve had but at the same time I think it’s the most enjoyable and useful so far. And finally I hear it’s very useful for programmers in computation and 3D programming so it’s something I really want to understand.&lt;/p&gt;
&lt;p&gt;Life with Veronica is also working out, mainly because she’s awesome, and I went to a Taekwon-do training this week. Feels good to practice again!&lt;/p&gt;
</content></entry><entry><title>Ludum Dare 22 results!</title><id>http://jonashietala.se/blog/2012/01/21/ludum_dare_22_results/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2012/01/21/ludum_dare_22_results" rel="alternate"/><published>2012-01-21T21:27:47+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&amp;amp;uid=1895&quot;&gt;The results&lt;/a&gt; from &lt;a href=&quot;http://www.ludumdare.com/compo/2012/01/09/ludum-dare-22-results/&quot;&gt;Ludum Dare 22&lt;/a&gt; are in! I made the game &lt;a href=&quot;/blog/2011/12/19/sat-e/&quot;&gt;Sat-E&lt;/a&gt; for the 48 hour competition and I was &lt;a href=&quot;/blog/2011/12/28/postmortem_sat-e&quot;&gt;quite happy&lt;/a&gt; with it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#24 Community 3.71&lt;/strong&gt;&lt;br /&gt;
This one was really surprising, but welcome. I did post a cute picture of a korean k-pop star so I guess that’s why.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#40 Fun 3.38&lt;/strong&gt;&lt;br /&gt;
Fun is always great! I’m so happy ^^&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#49 Theme 3.69&lt;/strong&gt;&lt;br /&gt;
I thought my theme choice (Wall-E in space) was good, seems like other thought that too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#65 Overall 3.42&lt;/strong&gt;&lt;br /&gt;
This is supposedly the “best” category to do well in so I’m glad. I did a lot better than I thought I would…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#95 Humor 2.82&lt;/strong&gt;&lt;br /&gt;
Damned blast I should’ve focus more on the funny one-liners.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#167 Mood 2.92&lt;/strong&gt;&lt;br /&gt;
If I make a better version of the game this is probably the one thing I would focus on. But that is a thought for another time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#247 Innovation 2.69&lt;/strong&gt;&lt;br /&gt;
Not very innovating I agree.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#338 Audio 2.23&lt;/strong&gt;&lt;br /&gt;
No music = shit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#340 Graphics 2.62&lt;/strong&gt;&lt;br /&gt;
I guess I’m not that good of an artist, but tell me something I don’t know!§&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#376 Coolness 35%&lt;/strong&gt;&lt;br /&gt;
The coolness factor = amount of games rated. I wasn’t motivated at all sadly… I’m a game developer but I don’t play much games? I’m so strange.&lt;/p&gt;
</content></entry><entry><title>2011 in Review</title><id>http://jonashietala.se/blog/2012/01/04/2011_in_review/index.html</id><updated>2023-10-01T13:14:41+00:00</updated><link href="https://www.jonashietala.se/blog/2012/01/04/2011_in_review" rel="alternate"/><published>2012-01-04T10:49:12+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s time to wrap up the year that’s been. Be warned for slight ego boosting here.&lt;/p&gt;
&lt;h1&gt;2011 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Wrote three games this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2011/05/02/my_minions/&quot;&gt;My Minions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2011/10/19/grand_thief_arto/&quot;&gt;Grand Thief Arto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2011/12/19/sat-e/&quot;&gt;Sat-E&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bought a &lt;a href=&quot;/blog/2011/08/21/new_computer&quot;&gt;new computer&lt;/a&gt;!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bought a mechanical keyboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bought &lt;a href=&quot;/blog/2011/12/16/starcraft_2_keycaps&quot;&gt;custom Starcraft 2 keycaps&lt;/a&gt; for the keyboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned 68k assembly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned about algorithms and data structures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bought a lot of programming books.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Pragmatic Programmer&lt;/li&gt;
&lt;li&gt;Structure and Interpretation of Computer Programs&lt;/li&gt;
&lt;li&gt;Introduction to Algorithms&lt;/li&gt;
&lt;li&gt;Modern Perl&lt;/li&gt;
&lt;li&gt;Effective Java&lt;/li&gt;
&lt;li&gt;Learn You a Haskell for Great Good!&lt;/li&gt;
&lt;li&gt;Land of Lisp&lt;/li&gt;
&lt;li&gt;Maybe something more…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a lot of programming books. Modern Perl and The Pragmatic Programmer were my favourites.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned some Ada.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned a lot of Perl.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned a tiny bit of Haskell.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned some &lt;a href=&quot;http://www.gnu.org/software/emacs/&quot;&gt;emacs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Got a hint of design understanding thanks to &lt;a href=&quot;http://www.designforhackers.com/&quot;&gt;Design for Hackers&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2011 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Went to a dance course with Veronica.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My stumach is in good shape!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read and loved A Song of Ice and Fire.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Achieved 7 kup in Taekwon-do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a &lt;em&gt;lot&lt;/em&gt; of manga. Some recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bakuman. A nice slice of life manga about… making manga. Surprisingly captivating.&lt;/li&gt;
&lt;li&gt;Gamaran. A slightly brutal battle manga with loads of weapons.&lt;/li&gt;
&lt;li&gt;Vinland Saga. A bit more brutal battle manga about vikings and war.&lt;/li&gt;
&lt;li&gt;Beelzebub. Battle manga but with a ton of light hearted humor.&lt;/li&gt;
&lt;li&gt;The Breaker. Another battle manga, a bit more direct perhaps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2011 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Didn’t produce enough games.&lt;/li&gt;
&lt;li&gt;Didn’t write enough code.&lt;/li&gt;
&lt;li&gt;Did not learn enough Haskell.&lt;/li&gt;
&lt;li&gt;Have a lot of books I haven’t read yet.&lt;/li&gt;
&lt;li&gt;Did not have enough free time.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2012&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Keep Veronica happy!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make more games.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Code more! Much more!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blog more!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learn more Haskell (yet again)…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transform my site to something new, something that I don’t dread to use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Improve in Taekwon-do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Be more disciplined in studying, coding, training and cleaning.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read the programming books I have but have not read yet.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A book about Erlang.&lt;/li&gt;
&lt;li&gt;K&amp;amp;R C Programming language.&lt;/li&gt;
&lt;li&gt;SICP, all important for every programmers. I hear.&lt;/li&gt;
&lt;li&gt;Probably missed something… Damn I’ve got many.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get good results in school.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Try to be a bit more social (it’s hard).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get more free time somehow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complete a larger personal project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learn more mathematics.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><title>Postmortem: Sat-E</title><id>http://jonashietala.se/blog/2011/12/28/postmortem_sat-e/index.html</id><updated>2026-04-27T11:10:26+00:00</updated><link href="https://www.jonashietala.se/blog/2011/12/28/postmortem_sat-e" rel="alternate"/><published>2011-12-28T19:22:02+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is my postmortem for my &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&quot;&gt;Ludum Dare 22&lt;/a&gt; entry, &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&amp;amp;uid=1895&quot;&gt;Sat-E&lt;/a&gt;. You can find the timelapse &lt;a href=&quot;http://www.ludumdare.com/compo/2011/12/19/sat-e-timelapse&quot;&gt;over here&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/ld22-lone.png&quot; /&gt;
&lt;/figure&gt;
&lt;h1&gt;The Good&lt;/h1&gt;
&lt;h2&gt;Motivation&lt;/h2&gt;
&lt;p&gt;I was really motivated for &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&quot;&gt;this dare&lt;/a&gt; and it showed in the game and outside it. It’s super hard to make a game in only 48 hours but this time it went pretty well. My &lt;a href=&quot;/blog/2011/05/02/my_minions/&quot;&gt;previous&lt;/a&gt; &lt;a href=&quot;/blog/2010/04/26/beebop_the_island_hopper/&quot;&gt;attempts&lt;/a&gt; went okay, but there were always something lacking. &lt;a href=&quot;/blog/2011/12/19/sat-e/&quot;&gt;This time&lt;/a&gt; the game feels a little bit more finished so I’m going in the right direction.&lt;/p&gt;
&lt;p&gt;After the game the programming motivation continued and with it I’ve been improving &lt;a href=&quot;https://codeberg.org/treeman/7days&quot;&gt;my small fast prototyping framework&lt;/a&gt; I use when making games. I got a lot of ideas on improvements during the weekend so that’s great.&lt;/p&gt;
&lt;h2&gt;The feedback&lt;/h2&gt;
&lt;p&gt;I was moderately happy with how the game turned out, it didn’t contain everything I had envisioned after all, but I got a &lt;em&gt;ton&lt;/em&gt; of positive feedback anyway which is wonderful! It seems like some thinks that my game is good and there’s nothing better for your game making confidence than a bunch of flattering words. I’m even considering developing the game more, maybe spending a couple of days here and there on it during a couple of months when I have the time?&lt;/p&gt;
&lt;h2&gt;I learned a lot!&lt;/h2&gt;
&lt;p&gt;The best way to learn something is &lt;em&gt;just to do&lt;/em&gt; and it’s still true. I’ve found a bunch of ways to improve and shorten my code, I’ve made an “infinite” space constructed by individual chunks and that game physics != real physics. Awesome.&lt;/p&gt;
&lt;p&gt;Game design is a pretty fascinating creature. Sometimes you give it your best but the resulting game isn’t funny, other times you think your game is shit but then you get comments on your “amazing” game! This time I was &lt;em&gt;certain&lt;/em&gt; the game was crap, a neat idea wrapped behind a boring gameplay but turns out it maybe wasn’t that boring after all?&lt;/p&gt;
&lt;p&gt;I got this comment:&lt;br /&gt;
“Also the fact that when that happened the game didn’t simply reset, I lost my money but not my items,
literally stopped me from rage quitting. Bravo”&lt;/p&gt;
&lt;p&gt;My thougts? Wait that’s a bug! Hmm…&lt;/p&gt;
&lt;h2&gt;My girlfriend&lt;/h2&gt;
&lt;p&gt;Of course as I live together with someone it’s quite hard to devote an entire weekend, plus the extra time before and after, with my computer. Veronica handled it wonderfully well and she was very supportive which means a lot to me and it helped a ton.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/ld22-lots.png&quot; /&gt;
&lt;/figure&gt;
&lt;h1&gt;The Bad&lt;/h1&gt;
&lt;h2&gt;The music&lt;/h2&gt;
&lt;p&gt;There’s no music but I had grand plans for making music for the first time ever! It failed hard though. Which brings me to the next point…&lt;/p&gt;
&lt;h2&gt;Not familiar with the tools&lt;/h2&gt;
&lt;p&gt;I used &lt;a href=&quot;https://codeberg.org/treeman/7days&quot;&gt;my own framework&lt;/a&gt; for the game, which is fine, but my &lt;a href=&quot;/blog/2011/05/02/my_minions/&quot;&gt;last game&lt;/a&gt; with it was in May 2011! Which is a looong time ago. I was a bit (a lot) out of practice with this whole pixel arts thing. And of course I had never used &lt;a href=&quot;http://lmms.sourceforge.net/&quot;&gt;LMMS&lt;/a&gt; to make music and that didn’t happen. I was short of time and it was too big of a deal to start it with the last minute.&lt;/p&gt;
&lt;h2&gt;Not enough time&lt;/h2&gt;
&lt;p&gt;Even though I had the whole weekend planned for the dare and I skipped practice on Sunday I was &lt;em&gt;still&lt;/em&gt; short on time. I’m not really sure why though. I made a pretty simple game, not a lot of art and I generated sound with &lt;a href=&quot;http://www.bfxr.net/&quot;&gt;bfxr&lt;/a&gt; which took no time at all… The reasons really must be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Not enough practice.&lt;/li&gt;
&lt;li&gt;Unfamiliarity with the tools. Correlates closely to #1.&lt;/li&gt;
&lt;li&gt;I’m bad and LD is hard.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When I see &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&quot;&gt;all&lt;/a&gt; &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&amp;amp;uid=8158&quot;&gt;these&lt;/a&gt; &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&amp;amp;uid=2982&quot;&gt;amazing&lt;/a&gt; &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&amp;amp;uid=527&quot;&gt;games&lt;/a&gt; I’m reminded on how much better other game makers are. I need more practice and I need to make more games. I should enter the next dare, enter &lt;a href=&quot;http://experimentalgameplay.com/&quot;&gt;the experimental gameplay project&lt;/a&gt; and just &lt;em&gt;make more games&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;And let’s face it: Making a game in 48 hours is frickin &lt;em&gt;hard&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;The Ugly&lt;/h1&gt;
&lt;h2&gt;The art&lt;/h2&gt;
&lt;p&gt;Oh god… I suck at making art. Let’s just leave it at that.&lt;/p&gt;
&lt;h2&gt;The code&lt;/h2&gt;
&lt;p&gt;There’s a lot of bad and wrong in there, it works but it’s not pretty. In fact, it’s ugly.&lt;/p&gt;
&lt;h2&gt;The gameplay&lt;/h2&gt;
&lt;p&gt;This is a tricky one. I thought about placing this in the bad section as I didn’t find the game very pleasing at all. The beginning was too slow, the ending too long and there wasn’t enough incentive to continue flying through endless space I thought. But I got a lot of positive comments and reactions which is wonderful! I don’t fully understand why yet so I’m tagging the gameplay as ugly. After all the gameplay wasn’t like in my dream…&lt;/p&gt;
&lt;h1&gt;Ending thoughts&lt;/h1&gt;
&lt;p&gt;Before entering the competition I’m always nervous but high spirited. That feeling is always crushed during the weekend and when I finally get the game done and uploaded I think it’s the worst game ever. Luckily I’m greeted with positive feedback and that was the case this time again. Maybe they are okay, not super of course, but simply okay.&lt;/p&gt;
&lt;p&gt;This time the dare came at a time where I felt I haven’t done anything meaningful for a long time, it’s just school, little programming and no game making. Now after my spirits are high and I can face a new year with many more games to come!&lt;/p&gt;
&lt;p&gt;Until next time, cheers!&lt;/p&gt;
</content></entry><entry><title>Ludum Dare 22 Timelapse</title><id>http://jonashietala.se/blog/2011/12/19/ludum_dare_22_timelapse/index.html</id><updated>2024-06-27T07:47:29+00:00</updated><link href="https://www.jonashietala.se/blog/2011/12/19/ludum_dare_22_timelapse" rel="alternate"/><published>2011-12-19T20:13:37+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Here’s the timelapse for my entry to &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare 22&lt;/a&gt;, &lt;a href=&quot;/blog/2011/12/19/sat-e/&quot;&gt;Sat-E&lt;/a&gt;.&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=eoKDyhxCVm0&quot;&gt;https://www.youtube.com/watch?v=eoKDyhxCVm0&lt;/a&gt;
&lt;p&gt;This time I managed to record one screen every minute, which is very suboptimal to say the least but I slowed it down a bit so you can at least see something being done there.&lt;/p&gt;
</content></entry><entry><title>Sat-E</title><id>http://jonashietala.se/blog/2011/12/19/sat-e/index.html</id><updated>2026-04-27T11:10:44+00:00</updated><link href="https://www.jonashietala.se/blog/2011/12/19/sat-e" rel="alternate"/><published>2011-12-19T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I entered &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare 22&lt;/a&gt; this weekend as a preamble for tomorrow’s linear algebra exam. The theme this time around was &lt;em&gt;Alone&lt;/em&gt; and the game I came up with is about a lonely satellite in space, kinda like Wall-E.&lt;/p&gt;
&lt;h1&gt;Sat-E&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/ld22-lone-small.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/ld22-dock-small.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/ld22-lots-small.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Instructions&lt;/h1&gt;
&lt;p&gt;Collect junk and other items for you to buy upgrades, and finally, your friend to finish the game. Be careful not to run out of battery, you need to return home to base for a recharge between runs.&lt;/p&gt;
&lt;h1&gt;Controls&lt;/h1&gt;
&lt;p&gt;Arrow Keys - Move around&lt;br /&gt;
Space/Return - Choose item in docking mode&lt;br /&gt;
F1 - Developer console&lt;/p&gt;
&lt;h1&gt;Timelapse&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=eoKDyhxCVm0&quot;&gt;It’s on youtube&lt;/a&gt; and it’s embedded &lt;a href=&quot;/blog/2011/12/19/ludum_dare_22_timelapse&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://codeberg.org/treeman/Sat-E&quot;&gt;https://codeberg.org/treeman/Sat-E&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Built using my fast prototyping framework&lt;br /&gt;
&lt;a href=&quot;https://codeberg.org/treeman/7days&quot;&gt;https://codeberg.org/treeman/7days&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>Starcraft 2 Keycaps</title><id>http://jonashietala.se/blog/2011/12/16/starcraft_2_keycaps/index.html</id><updated>2024-06-18T23:45:20+00:00</updated><link href="https://www.jonashietala.se/blog/2011/12/16/starcraft_2_keycaps" rel="alternate"/><published>2011-12-16T16:44:59+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;When I ordered this computer I was compelled, utterly compelled to buy a mechanical keyboard. Sure they cost almost 10x as much as a “regular” one and they didn’t even have these funky multimedia keys, what gives? Did I loose my insanity? It was supposed to give a great typing experience… And it sure did deliver!&lt;/p&gt;
&lt;p&gt;I’m bringing this up again because I decided to spend my money on something possibly even more useless (or awesome?). I ordered some starcraft II modifier keys for the keyboard and now they are fitted onto the keyboard. Yay!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/starcraft2_kb.jpg&quot; /&gt;
&lt;/figure&gt;</content></entry><entry><title>Ludum Dare 22 Here I Come</title><id>http://jonashietala.se/blog/2011/12/14/ludum_dare_22_here_i_come/index.html</id><updated>2026-04-27T11:10:11+00:00</updated><link href="https://www.jonashietala.se/blog/2011/12/14/ludum_dare_22_here_i_come" rel="alternate"/><published>2011-12-14T09:25:31+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The time has finally come. After more than three hours of exam writing, and almost double spent on studying for it, I am now ready to declare my entry into &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare 22&lt;/a&gt;! I’ve been away far too long, with my entries for the &lt;a href=&quot;/blog/2010/04/26/beebop_the_island_hopper/&quot;&gt;17th&lt;/a&gt; and the &lt;a href=&quot;/blog/2011/05/02/my_minions/&quot;&gt;20th&lt;/a&gt; dare being almost a century away, the ancient game making creature will once again move into action. We’ll just hope the game won’t be ancient as well…&lt;/p&gt;
&lt;p&gt;Leaving that behind us I can now focus on what to actually &lt;em&gt;use&lt;/em&gt;. I wanted to try some new language and some new environment but that seems lika a really bad idea. So I will stick to what I know:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/7days&quot;&gt;My fast prototyping library&lt;/a&gt; consisting of old C++ on top of the nice &lt;a href=&quot;http://www.sfml-dev.org/&quot;&gt;SFML&lt;/a&gt; engine.
&lt;a href=&quot;http://www.drpetter.se/project_sfxr.html&quot;&gt;sfxr&lt;/a&gt;, or maybe the newer &lt;a href=&quot;http://www.bfxr.net/&quot;&gt;bfxr&lt;/a&gt; for sound effects. It’s seriously great, give it a try!
Probably &lt;a href=&quot;http://mtpaint.sourceforge.net/&quot;&gt;mtpaint&lt;/a&gt; for some nice pixelated graphics. I would like to try out &lt;a href=&quot;http://inkscape.org/&quot;&gt;inkscape&lt;/a&gt; for some vector based graphics but I might skip it this time.
&lt;a href=&quot;http://lmms.sourceforge.net/&quot;&gt;LMMS&lt;/a&gt; for music making. This I tried to use a long time ago… And failed miserably. It’ll be a fun, fun weekend!
And finally my little &lt;a href=&quot;https://github.com/treeman/Treebot&quot;&gt;timelapse recording hack&lt;/a&gt; for linux. Be careful if you want to try it, it will most likely blow up in your face and take your computer down with it. Handle with care.&lt;/p&gt;
&lt;p&gt;And of course here’s where I’ll be spending most of my waking hours:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/LD_setup.jpg&quot; /&gt;
&lt;figcaption&gt;Ludum Dare 22 setup&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’m planning on getting some new food during all this, but I’m not entirely sure yet.&lt;/p&gt;
</content></entry><entry><title>On The Decline of FPS Games</title><id>http://jonashietala.se/blog/2011/12/12/on_the_decline_of_fps_games/index.html</id><updated>2023-10-13T17:12:44+00:00</updated><link href="https://www.jonashietala.se/blog/2011/12/12/on_the_decline_of_fps_games" rel="alternate"/><published>2011-12-12T22:05:30+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Mr. Eriksson just sent me this link as a fitting video on my post on &lt;a href=&quot;/blog/2011/11/20/the_decline_of_fps_games&quot;&gt;The Decline of FPS Games&lt;/a&gt;.&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=W1ZtBCpo0eU&quot;&gt;https://www.youtube.com/watch?v=W1ZtBCpo0eU&lt;/a&gt;
&lt;p&gt;Oh How true!&lt;/p&gt;
</content></entry><entry><title>Finishing Stuff</title><id>http://jonashietala.se/blog/2011/12/07/finishing_stuff/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/12/07/finishing_stuff" rel="alternate"/><published>2011-12-07T09:28:37+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I haven’t done much blogging or game programming in a while but instead I’ve finished some school stuff. We completed the assembly course labs, which were pretty fun actually, and I managed to finally complete the electronics course I’ve been holding off on for like forever… But now it’s gone, yay!&lt;/p&gt;
&lt;p&gt;There’s not much left before christmas either, we have some sort of exam on tuesday (very boring course) and one the 20th (very fun course) but other than that I’m free to do whatever I want.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I’m planning on entering &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare&lt;/a&gt; next weekend, finally getting some game programming done.&lt;/li&gt;
&lt;li&gt;I need to recap this year and plan some for the next. I fear this year wasn’t as productive as I had hoped.&lt;/li&gt;
&lt;li&gt;I’ve been thinking that I know my tools (Vim, the command line) but I need to get a little bit better. Especially with emacs as I feel like a monkey on a typewriter when I’m forced to use it at school. Not cool.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And some more smaller stuff I don’t have energy to type out (or maybe you’re interested in reorganizing my home folder?).&lt;/p&gt;
</content></entry><entry><title>A Nice Weekend</title><id>http://jonashietala.se/blog/2011/11/21/a_nice_weekend/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/11/21/a_nice_weekend" rel="alternate"/><published>2011-11-21T11:07:14+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve had a pretty nice weekend. On Friday MLG Orlando began and I’ve been staying up to 2 and sleeping until at least 10 the last days. My inner night-owl is very happy about it, my early-rising girlfriend perhaps not as much, but I think she’s a bit understanding?&lt;/p&gt;
&lt;p&gt;On Saturday we cleaned the house for Christmas and hung up a star and stuff like that. It was brutally hard work (laugh if you like) but I pulled through without dying too much. Saturday night was full of StarCraft again though so it’s fine!&lt;/p&gt;
&lt;p&gt;What about Sunday then? Even more StarCraft of course!! IPL had some grand tournament, which Stephano won of course, and MLG had it’s final day. In the middle there somewhere we had some taekwon-do and I did some laundry. With that done I sat and shouted at my chosen ones in the tournament and they did do okay, not like I had hoped but still. Leenock managed to win MLG which is pretty damn awesome.&lt;/p&gt;
&lt;p&gt;Now I need to adapt to a normal life again, with school and &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare&lt;/a&gt; coming up.&lt;/p&gt;
</content></entry><entry><title>The Decline of FPS Games</title><id>http://jonashietala.se/blog/2011/11/20/the_decline_of_fps_games/index.html</id><updated>2023-10-13T17:12:47+00:00</updated><link href="https://www.jonashietala.se/blog/2011/11/20/the_decline_of_fps_games" rel="alternate"/><published>2011-11-20T11:39:25+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I read &lt;a href=&quot;http://au.pc.ign.com/articles/121/1212393p1.html&quot;&gt;an article about the decline of FPS games&lt;/a&gt; and it made me think a bit. When was the last time I actually enjoyed an FPS game? I installed old &lt;a href=&quot;http://en.wikipedia.org/wiki/Deus_Ex&quot;&gt;Deus Ex&lt;/a&gt; a while ago but it’s what 12 years old? &lt;a href=&quot;http://www.teamfortress.com/&quot;&gt;Team Fortress&lt;/a&gt; was okay, the one or two times I tried it, but I can’t say I truly enjoyed it, hell I never even played it apart from trying it at a friends pc. Well I bought &lt;a href=&quot;http://en.wikipedia.org/wiki/Duke_Nukem_Forever&quot;&gt;Duke Nukem Forever&lt;/a&gt; but I haven’t even completed it, it’s best server collecting dust at the bookshelf now. No the truly last FPS I enjoyed was &lt;a href=&quot;http://store.steampowered.com/app/240/&quot;&gt;CSS&lt;/a&gt;. How is this possible?&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse4.mm.bing.net%2Fth%3Fid%3DOIP.R4Igz3Hc2dQfUvlghvcepgHaEK%26pid%3DApi&amp;amp;f=1&amp;amp;ipt=69568e6ad99f46906d2aea8de1c7cd3ec483678e5a2817d413093e151ab61f79&amp;amp;ipo=images&quot; /&gt;
&lt;figcaption&gt;CSS: my one favorite FPS game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I am not a big FPS fan and I get sick of modern FPS almost directly. It feels like they are all the same, I don’t even want to try them anymore. The biggest upset was actually &lt;a href=&quot;http://en.wikipedia.org/wiki/Duke_Nukem_Forever&quot;&gt;Duke Nukem Forever&lt;/a&gt; lately. It had totally linear levels, you could only use two weapons at a time and it just felt boring and uninspiring. Why is it that FPS games are considered good if the graphics is good? Or have an advanced physics engine? It’s good of course but there has to be more to a game than that. Games feel so shallow nowadays.&lt;/p&gt;
&lt;p&gt;But I never did think about FPS games when I read the article no I thought about RTS and construction games. The main point the article wanted to put forward is that game designers today, especially big ones, don’t want to take big risks so they do the same thing as everyone else. This is what happened a decade or go or something when we got a bunch of very similar RTS games. I remember that there were a lot of very similar construtor games before that too. But where are they now? I don’t want a million similar titles, but the basic ideas behind those games were great - and I miss them.&lt;/p&gt;
&lt;p&gt;Where is Evil Genius 2 for example? It’s one of the best games ever but there’s nothing similar, only a bunch of similar games trying to steal the popularity of other, probably better, games in the same style.&lt;/p&gt;
&lt;p&gt;We need to stop imitating and start innovating, but we also need to bring back the ideas of the classics.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;http://static2.cdn.ubi.com/emea/gamesites/anno/pc/content/screen1602_1_large.jpg&quot; /&gt;
&lt;figcaption&gt;Anno 1602, one of many classic constructor games. But where are they now?&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Swelling with New Shiny Books</title><id>http://jonashietala.se/blog/2011/11/09/swelling_with_new_shiny_books/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/11/09/swelling_with_new_shiny_books" rel="alternate"/><published>2011-11-09T21:41:09+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I read the wonderful &lt;a href=&quot;http://www.designforhackers.com/&quot;&gt;Design for Hackers&lt;/a&gt; and I managed to win some money for books from a course… So I ran away and ordered some new books, and they just arrived today. Yay!&lt;/p&gt;
&lt;p&gt;First off I ordered &lt;a href=&quot;http://highered.mcgraw-hill.com/sites/0070131511/&quot;&gt;Introduction to Algorithms&lt;/a&gt; which is the de facto book about algorithms and it seemed like a fitting thing to do as I won it by doing algorithm assignments.&lt;/p&gt;
&lt;p&gt;Secondly I’ve been wanting to grab &lt;a href=&quot;http://mitpress.mit.edu/sicp/full-text/book/book.html&quot;&gt;Structure and Interpretation of Computer Programs&lt;/a&gt; for a while and I finally did. It’s one of the classical computer books you &lt;em&gt;have&lt;/em&gt; to read once in your life (or so they say).&lt;/p&gt;
&lt;p&gt;I wasn’t going to get a third book, but on &lt;a href=&quot;http://adlibris.com/&quot;&gt;adlibris&lt;/a&gt; where I got the vouchers you couldn’t pay with two vouchers on one order. So I had to split it up and it felt kinda dumb to not use it all… So I ordered a third book. I had no idea what book to get though, but &lt;a href=&quot;http://stackoverflow.com/questions/1711/what-is-the-single-most-influential-book-every-programmer-should-read&quot;&gt;stackoverflow&lt;/a&gt; came to the rescue! It’s a bunch of answers to the question “What is the single most influential book every programmer should read?” and is like a top X list for programming books.&lt;/p&gt;
&lt;p&gt;Incidentally I’ve got a few of those already, and the two I’ve already decided on was there (SICP is 3rd, Introduction to Algorithms 5th). Of course I wanted to get either the 1st or 2nd and I ended up choosing the 2nd one, &lt;a href=&quot;http://pragprog.com/the-pragmatic-programmer&quot;&gt;The Pragmatic Programmer&lt;/a&gt; just because it seemed a bit easier to read. I’ve got a ton of fairly hardcore programming books I need to plow through so something a bit easier to digest should be welcome.&lt;/p&gt;
&lt;p&gt;Go go programming books!&lt;/p&gt;
</content></entry><entry><title>Done this, done that. What now?</title><id>http://jonashietala.se/blog/2011/11/05/done_this_done_that_what_now/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/11/05/done_this_done_that_what_now" rel="alternate"/><published>2011-11-05T16:01:17+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Finished and uploaded our java game &lt;a href=&quot;/blog/2011/10/19/grand_thief_arto/&quot;&gt;Grand Thief Arto&lt;/a&gt;, done an exam (didn’t quite go as intended) and starting some new courses in school. I’m liking my choice of Computer Science more and more. &lt;em&gt;Data structures and Algorithms&lt;/em&gt; was a super fun course, I actually ordered a &lt;a href=&quot;http://highered.mcgraw-hill.com/sites/0070131511/&quot;&gt;new book about the subject&lt;/a&gt; just yesterday. &lt;em&gt;Linear Algebra&lt;/em&gt; is really fun now as we’re getting deeper into it and we’re looking into assembly and processor structures now too. &lt;em&gt;Awesome&lt;/em&gt;. I can’t believe I considered doing physics or electronics when I could take these courses. Now if I only could do operating systems, compiler construction and language design…&lt;/p&gt;
&lt;p&gt;In the meantime I’ve finished &lt;a href=&quot;/blog/2011/09/16/design_for_hackers&quot;&gt;Design for Hackers&lt;/a&gt; and it was a really nice book to be honest. I never knew there was so much about design and now I keep noticing funky stuff like what font a particular website is using, what colors and how they direct the reader. I also see a lot of inadequate stuff on my page and I have a few things I’d like to try.&lt;/p&gt;
&lt;p&gt;I also read &lt;a href=&quot;http://en.wikipedia.org/wiki/Watchmen&quot;&gt;Watchmen&lt;/a&gt;, the comic, and it was absolutely wonderful. Sadly I saw the movie before but, naturally, the comic was a lot better. So wonderfully dark and ah… Simply awesome.&lt;/p&gt;
</content></entry><entry><title>Design for Hackers has arrived!</title><id>http://jonashietala.se/blog/2011/10/19/design_for_hackers_has_arrived/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/10/19/design_for_hackers_has_arrived" rel="alternate"/><published>2011-10-19T21:25:57+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;figure&gt;
&lt;img src=&quot;http://designforhackers.com/wp-content/themes/D4H/img/book-image.jpg&quot; /&gt;
&lt;figcaption&gt;Design for Hackers&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It’s here! After about a month of waiting I’ve finally gotten the book that will make me a design god! Or at least make me &lt;em&gt;aware&lt;/em&gt; of something called design. Joking aside I’m really terrible at design and making things look good. Admittedly my programming art for my games has gradually improved but I honestly don’t know what I’m doing, I just mess around until I get something decent. Maybe this can be a small aid? I even have some websites I want to design, and while I’m at it I want to try the &lt;a href=&quot;http://mojolicio.us/&quot;&gt;Perl web framework mojolicious&lt;/a&gt; which looks totally awesome!&lt;/p&gt;
</content></entry><entry><title>The End of the Tunnel</title><id>http://jonashietala.se/blog/2011/10/19/the_end_of_the_tunnel/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/10/19/the_end_of_the_tunnel" rel="alternate"/><published>2011-10-19T21:18:24+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Lately I’ve been feeling like there’s been a shit-ton of stuff going on, quite a turn-around from the &lt;a href=&quot;/blog/2011/09/30/being_productive&quot;&gt;last time&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One course about data structure and algorithms (super fun to be honest) has wrapped up. We thought we were ahead with the assignments but in the end it got very stressful. I sat up pretty late trying to optimize our code from 0.16 to below 0.15 seconds and it almost drove me crazy…&lt;/p&gt;
&lt;p&gt;My last resort was to convert all strings to integers and do some funky bit shifting operations but it got too late so I had to go to sleep before making it work correctly. Of course I couldn’t sleep and I lay and thought about all the things I didn’t do or where I could’ve messed up. I woke really early, couldn’t sleep, and I went to fix it before our presentation that morning and look and behold! It was fixed in less than 15 minutes and it was blazingly fast! It’s funny how sleep or a nice shower can solve almost any problem you have, except hunger I guess.&lt;/p&gt;
&lt;p&gt;While this was going on I also took part in a competition of some sorts in connection with the course. There was a programming problem after each lecture that we had to complete and the goal was to get as few hours as possible after the problems were released. Most problems were quite easy but there were a few hard ones. One I also lost some sleep over! But again I woke up and had to run to the computer to try to solve it… At least I won some money for some lovely new books so I guess it was worth it.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/sneak.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;We’re now finishing our other course, &lt;a href=&quot;/blog/2011/09/12/10_games_in_10_languages&quot;&gt;the one with the Java game that spurred me to wanna make more games&lt;/a&gt;, and I think I spent a bit too much time on that… The game turned out pretty cool, I will make a post about it tomorrow I think, but it was a level or two above the actual demands I think so we could’ve chilled and not stress that much. And now we &lt;em&gt;only&lt;/em&gt; have to document it! Describe how all the classes work with UML and some blocks of text… Sigh.&lt;/p&gt;
&lt;p&gt;And oh yeah, we had totally forgotten to write a project specification that was supposed to be handed in over a month ago and we had completely missed the deadlines for the &lt;em&gt;other&lt;/em&gt; assignments in that course. Luckily the deadlines were only suggestions and our assistant was cool about the specification too so we survived with our head still intact.&lt;/p&gt;
&lt;p&gt;It just seems so silly though. Why did we wait with the other assignments, I think I did them in one day or something, until the very last second? It seems like I’ve been here before, and I don’t like it. This time I had a bit more control over the whole situation but it’s still not quite good enough.&lt;/p&gt;
&lt;p&gt;Anyway now when this is all finishing up I can start to relax again. But then the thought creeps up on me: what’s next?&lt;/p&gt;
&lt;p&gt;I’m probably gonna program, make a game or two, go through a language, read some books, train a lot… Urr I’m getting all stressed out just thinking out loud like that!&lt;/p&gt;
&lt;p&gt;No I need to relax. Maybe read some more manga? Yes, that is indeed a good idea…&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/WwR5X.jpg&quot; /&gt;
&lt;figcaption&gt;manga…&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Grand Thief Arto</title><id>http://jonashietala.se/blog/2011/10/19/grand_thief_arto/index.html</id><updated>2024-06-27T07:47:52+00:00</updated><link href="https://www.jonashietala.se/blog/2011/10/19/grand_thief_arto" rel="alternate"/><published>2011-10-19T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Here’s me and Li’s game for our school course. The game isn’t tweaked too much but it’s a game with some fairly cool ideas.&lt;/p&gt;
&lt;h1&gt;Grand Thief Arto&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/arto1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/arto2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/arto3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Instructions&lt;/h1&gt;
&lt;p&gt;Your goal is to collect loot until you can escape through the entry point when you’ve collected enough to complete the level.&lt;/p&gt;
&lt;p&gt;There are touchpads and lasers you need to shutdown by walking next to a computer or an electric board and shut them down from there. Otherwise you need to open doors and then just run around and collect.&lt;/p&gt;
&lt;p&gt;You can either play by launching the bash script “play” directly in the folder or launch the game with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;java base.GameFrame
or
java -Xss2048k -Xms64m -Xmx1024m base.GameFrame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or whatever your preferred way of launching java apps is. You obviously need the java runtime, otherwise you might fetch it from &lt;a href=&quot;http://www.java.com/en/download/index.jsp&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You might need to create the binary files for it. Use the bash script “create” or do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;javac base.GameFrame
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it might not be necessary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controls&lt;/strong&gt;&lt;br /&gt;
Arrow keys - Walk around&lt;br /&gt;
Space - Do action&lt;br /&gt;
Esc - Menu&lt;/p&gt;
</content></entry><entry><title>Being Productive</title><id>http://jonashietala.se/blog/2011/09/30/being_productive/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/09/30/being_productive" rel="alternate"/><published>2011-09-30T14:30:21+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;School’s been going on now for… Is it a month and a half maybe? I don’t know really but it’s all going so fast, week after week is disappearing and I don’t know where they go but I know that I’m at least not wasting them like I did most of last year!&lt;/p&gt;
&lt;p&gt;Last year I managed school sure, but without doing anything special. Well if you don’t count watching nearly every GSL live (from 06-09 or 11-13 on weekdays) which is pretty awesome. But that’s also taking away a lot of time when I could’ve (and often should’ve) studied - sadly I skipped a lot of school last year. I admit GSL can’t explain it all, I was lazy okay!&lt;/p&gt;
&lt;p&gt;This year I’d like to a bit better and it has started out fine. I haven’t skipped a single lecture yet (Java doesn’t count!!) and I’m not too far behind in anything and a bit ahead in others, in summary I’m doing great, heh.&lt;/p&gt;
&lt;p&gt;Aside from school though, which is almost even more important, I’m feeling good and getting things done. Our home hasn’t burned down yet so that’s some success right there, but I’m taking it even farther and taking care of some cooking and stuff too, of course with Veronicas help but anyway. I’m also increasing my &lt;a href=&quot;/blog/2011/09/04/back_to_training&quot;&gt;Taekwon-do&lt;/a&gt; training, doing some reading and a bunch of other stuff. Programming too!&lt;/p&gt;
&lt;p&gt;I took the advice of &lt;a href=&quot;http://calnewport.com/blog/&quot;&gt;Cal Newport&lt;/a&gt; and now I actually plan my days, every day, on the morning or the night before. Here’s an example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0730 - 0900 Program&lt;/li&gt;
&lt;li&gt;0900 - 1000 Call OnOff, electric company, DN, corren&lt;/li&gt;
&lt;li&gt;1000 - 1100 Program&lt;/li&gt;
&lt;li&gt;1100 - 1130 Food&lt;/li&gt;
&lt;li&gt;etc..&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course I don’t really follow it to each and every point, but it helps me know what I need to get done this day. Often I skip and I reorder and I do other stuff a lot but if I’ve done at least half of what I set out to do I’ve been more productive than I’d usually be! And I even remember to do stuff like make a prenumeration on DN which I would &lt;em&gt;never&lt;/em&gt; had otherwise.&lt;/p&gt;
&lt;p&gt;Something else that’s helped me is a regular and healthy sleeping pattern - go to sleep and wake up at the same time, every day.&lt;/p&gt;
&lt;p&gt;I’m feeling good about school and everything but I’ve got stuff left to do so don’t see it as a perfect example - far from it to be sure, but it’s a step in the right direction I guess.&lt;/p&gt;
</content></entry><entry><title>Design for Hackers</title><id>http://jonashietala.se/blog/2011/09/16/design_for_hackers/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/09/16/design_for_hackers" rel="alternate"/><published>2011-09-16T16:28:48+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I get these.. urges sometimes. Not like &lt;a href=&quot;https://www.imdb.com/title/tt0773262/&quot;&gt;Dexter&lt;/a&gt; no, but sometimes I just &lt;em&gt;have&lt;/em&gt; to buy a specific thing. It happened again yesterday (or was it the day before I don’t know) when I saw &lt;a href=&quot;http://www.kadavy.net/blog/posts/d4h-is-here/&quot;&gt;this post&lt;/a&gt; on &lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;hackernews&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It’s a book this time, again, but this is something a little different - it’s about design. Now I know nothing about design but I’ve enjoyed designing some sites and I really like to design games but I don’t have a clue how to do it in a structural manner. I just try different colors and different stuff until “hey that looks kinda good” and it’s done! That’s not how you make something useful or something that looks good - good design. But this book seems to teach you just that!&lt;/p&gt;
&lt;p&gt;It’s a book for hackers, in the original non-journalistic definition, and it explains stuff in a logical manner! Now I might get a feel for why I think something looks good and I might even be able to improve on it? Happy times!&lt;/p&gt;
&lt;p&gt;The only issue is that I promised myself to not order any more programming books until I’ve gone through the ones I have - but this isn’t one so it should be okay! So now I made myself to promise that I’ll do the math assignments for the week and then I can order!&lt;/p&gt;
&lt;p&gt;Instead of writing this I really should do them then.&lt;/p&gt;
&lt;p&gt;Hrrmm…&lt;/p&gt;
</content></entry><entry><title>10 Games in 10 Languages</title><id>http://jonashietala.se/blog/2011/09/12/10_games_in_10_languages/index.html</id><updated>2023-10-13T17:13:37+00:00</updated><link href="https://www.jonashietala.se/blog/2011/09/12/10_games_in_10_languages" rel="alternate"/><published>2011-09-12T11:18:19+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;For school we have this programming course for Java. It isn’t anything special really and it would be really boring if I don’t like to program, it almost is anyway, if it weren’t for the fact that we’re to create a game! Just any game will do and we’re in a group of two and we have about a month to complete it. Mmh I like.&lt;/p&gt;
&lt;p&gt;Me and Li, my conspiring friend, have a pretty decent idea of something we can make. The only minor thing is that neither he nor I know anything about Java. Turns out I’ve done &lt;a href=&quot;/blog/tags/games/&quot;&gt;some gamemaking&lt;/a&gt; in mostly C++ and it’s really not different so we’ll see how the game finishes.&lt;/p&gt;
&lt;p&gt;Now this game me a bit of an idea, or rather it resurfaces and older idea, namely to make a few games in a couple of different languages. I like to explore different languages and I like to make games so why not combine them?&lt;/p&gt;
&lt;p&gt;I’ll try to make 10 different games with 10 different languages, starting with this Java game. I won’t make this one alone but that hardly matters I guess, there’s plenty of time to code in solitude later.&lt;/p&gt;
&lt;p&gt;These are some I had in mind:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Java&lt;br /&gt;
This one is slated for release in the middle of October&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;C++&lt;br /&gt;
I’m not sure if this one is considered cheating? I mean I’ve made a few already.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;C&lt;br /&gt;
I haven’t done much pure C, and this looks like a nice time as any.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lua&lt;br /&gt;
I’ve used you to change values without compiling before, but do you have more to offer me?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clojure&lt;br /&gt;
I do love lisp and as it runs on the JVM it shouldn’t be too different from Java.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scala&lt;br /&gt;
Scala is one of those languages you just &lt;em&gt;got&lt;/em&gt; to try someday. Also a JVM, piece of cake right?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Perl&lt;br /&gt;
Perhaps my current favorite language, it’s just so fun to write you know?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Python&lt;br /&gt;
When you’re gonna do the &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare&lt;/a&gt; many are recommending you to use Python with &lt;a href=&quot;http://pygame.org/&quot;&gt;PyGame&lt;/a&gt;, it’s time to find out why.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://jashkenas.github.com/coffee-script/&quot;&gt;Coffee-script&lt;/a&gt; + html 5&lt;br /&gt;
One of the more hyped up web technologies right now and I haven’t used them? Shame on me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Haskell&lt;br /&gt;
Oh Haskell, I’ve tried to get you down the last two summers but you won’t quite let me. Enough is enough, you’re going down!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I might change one or two later on if I find something better to try out (C++ is a bit lazy to include) and I certainly won’t do them in this order. There’s a big chance I won’t do them once a month either, but that’s the general goal I’m setting up.&lt;/p&gt;
&lt;p&gt;Now it’s time to do some other, more boring, school work…&lt;/p&gt;
</content></entry><entry><title>Back to Training</title><id>http://jonashietala.se/blog/2011/09/04/back_to_training/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/09/04/back_to_training" rel="alternate"/><published>2011-09-04T13:56:19+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Five days of school now and things are starting to settle down a bit. The courses are pretty cool; we have linear algebra which is pretty interesting, we have a java course where we’re going to make a game (!) and one about structures and algorithms. Pretty promising but we’ll see how things pan out.&lt;/p&gt;
&lt;p&gt;Taekwon-do practice has started and it’s awesome. In the beginning it’s so hard so I always wonder why I continue, but in the end it’s really fun and it feels good after. If you haven’t tried it you really should, or some other martial arts cause it’s pretty cool.&lt;/p&gt;
&lt;p&gt;It’s a perfect training for both mind and body. You might think it’s just mindless hardship thanks to all the martial arts movies/anime/manga with crazy training, but you’re also training your awareness, your creativity and decision making and more. Especially when sparring it’s absolutely paramount that your head is with you, doesn’t matter how fast or strong you are, if you don’t fight with your head you’re pretty screwed. That’s what I really like about it, it’s a pretty smart training.&lt;/p&gt;
&lt;p&gt;What I don’t like however, and this is totally unrelated to anything, is the rain! I went to school five days and I got soaking wet &lt;em&gt;five&lt;/em&gt; times! Hrblr… That’s why I’ve decided to do absolutely nothing today, I might watch some GSL and read a bit. I’ve got &lt;a href=&quot;http://learnyouahaskell.com/&quot;&gt;Learn you a Haskell for Great Good&lt;/a&gt;, &lt;a href=&quot;http://java.sun.com/docs/books/effective/&quot;&gt;Effective Java&lt;/a&gt; and &lt;a href=&quot;https://www.amazon.com/Thinking-Java-4th-Bruce-Eckel/dp/0131872486&quot;&gt;Thinking in Java&lt;/a&gt; who can hold me company a bit.&lt;/p&gt;
&lt;p&gt;And then there’s Taekwon-do training of course!&lt;/p&gt;
</content></entry><entry><title>Getting Comfortable</title><id>http://jonashietala.se/blog/2011/08/28/getting_comfortable/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/08/28/getting_comfortable" rel="alternate"/><published>2011-08-28T14:01:27+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I physically built &lt;a href=&quot;/blog/2011/08/21/new_computer&quot;&gt;the computer&lt;/a&gt; and now I’ve been using it a while, configuring stuff and getting used to my new screens. I think they’re about three times wide as my old laptop and now I have this one huge vertical space which is absolutely wonderful for surfing forums and reading code. Damn I love coding on it! When I go back to the laptop I feel cramped..&lt;/p&gt;
&lt;p&gt;And while we’re at dissing the old - I can never ever like another keyboard again! Well, at least not another rubber dome or scissor switch one.&lt;/p&gt;
&lt;p&gt;No this day forward I’m a mechanical keyboard fantast. You might think I’m crazy but the difference is pretty huge, before my fingers got tired but now they don’t and it’s even fun to type again!&lt;/p&gt;
&lt;p&gt;If that got you interested you need to read &lt;a href=&quot;http://geekhack.org/showwiki.php?title=START+HERE+--+The+Geekhack+Mechanical+Keyboard+Guide+-+Includes+Glossary+and+Links&quot;&gt;this geekhack post&lt;/a&gt;, it’s nice to say the least.&lt;/p&gt;
&lt;p&gt;Back to my screen setup again - yes everything with my new computer is either the monitors or the keyboard - I wanted to use &lt;a href=&quot;http://www.xmonad.org&quot;&gt;xmonad&lt;/a&gt; without relying on xfce this time. I like xfce as a truly lightweight window manager but a tiling window manager is just vastly superior, and the xfce statusbar is pretty ugly..&lt;/p&gt;
&lt;p&gt;I set up a nice looking statusbar and some stuff on the desktop with &lt;a href=&quot;http://conky.sourceforge.net/&quot;&gt;conky&lt;/a&gt;. I’ve been wanting to set up a todo list and while I was at it I put up my assignment due dates and my schedule too. And never forget the ever so important manga updates!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/xmonad-left.png&quot; width=&quot;180px&quot; /&gt;
&lt;img src=&quot;/images/xmonad-right.png&quot; width=&quot;400px&quot; /&gt;
&lt;figcaption&gt;My dual screen setup&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A nice little feature I added down on the right is the time in various timezones, they adjust to summer time on their own dates and they change the abbreviations too - from CEST to CET and so on.&lt;/p&gt;
&lt;p&gt;Something that didn’t go smooth at all is the gaming - I couldn’t ever get any games to work with wine! After a while I found out that an older driver solved the problem, but most games still don’t work with dual screen. So I kinda have to switch between two config files, but that works too I guess.&lt;/p&gt;
&lt;p&gt;All my config files are up on &lt;a href=&quot;http://github.com/treeman/dotfiles&quot;&gt;github&lt;/a&gt; as well if you’re interested.&lt;/p&gt;
</content></entry><entry><title>New Computer!</title><id>http://jonashietala.se/blog/2011/08/21/new_computer/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/08/21/new_computer" rel="alternate"/><published>2011-08-21T13:23:41+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I briefly mentioned my new computer in &lt;a href=&quot;/blog/2011/08/18/resurrection&quot;&gt;the last post&lt;/a&gt; and I thought I’d make a post about it, as it’s awesome (as all new computers are).&lt;/p&gt;
&lt;p&gt;The specs:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GPU:&lt;/strong&gt; Gigabyte GeForce GTX 550Ti OC 1GB&lt;br /&gt;
&lt;strong&gt;CPU:&lt;/strong&gt; Intel core i5 2500K&lt;br /&gt;
&lt;strong&gt;CPU cooler:&lt;/strong&gt; Zalman CNPS-9900NT&lt;br /&gt;
&lt;strong&gt;Motherboard:&lt;/strong&gt; MSI P67A-C45 REV B3&lt;br /&gt;
&lt;strong&gt;Ram:&lt;/strong&gt; Corsair 4GB (2x2048MB) CL9 1600Mhz XMS&lt;br /&gt;
&lt;strong&gt;Harddrive:&lt;/strong&gt; 1TB Samsung Spinpoint F3 HD103SJ&lt;br /&gt;
&lt;strong&gt;PSU:&lt;/strong&gt; FSP Aurum 400W 80+ Gold&lt;br /&gt;
&lt;strong&gt;Displays:&lt;/strong&gt; 2 x Dell U2211H ultrasharp 21,5“ widescreen&lt;br /&gt;
&lt;strong&gt;Keyboard:&lt;/strong&gt; Das Keyboard - Ultimate Model S Silent&lt;br /&gt;
&lt;strong&gt;DVD burner:&lt;/strong&gt; Samsung DVD±R/RW/RAM&lt;br /&gt;
&lt;strong&gt;Case:&lt;/strong&gt; Fractal Design Define R3, Black&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/overall1.jpg&quot; width=&quot;600&quot; /&gt;
&lt;figcaption&gt;The look&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I wanted the computer to be fast and silent and I &lt;em&gt;had&lt;/em&gt; to have two screens. I had a budget of 12,000 SEK and almost managed it too.&lt;/p&gt;
&lt;p&gt;The screens I chose are two fairly large widescreen IPL screens, very solid, but they quickly ate up about a third of my budget… In hindsight it was a good investment, they’re absolutely wonderful!&lt;/p&gt;
&lt;p&gt;The processor was fairly straightforward to choose - the i5 2500K is a beast for it’s price. I don’t really need 8GB ram, I think I’ve used 2GB max before so I just stuck with 4 this time. The motherboard is nothing special but I don’t need it to be either.&lt;/p&gt;
&lt;p&gt;I’ve got about 4TB of storage laying around here so I don’t need any more really, but I chose a relatively fast and silent 1TB disk. I’d love to get a SSD but I couldn’t squeeze that into the budget.&lt;/p&gt;
&lt;p&gt;Although you can say you don’t need a DVD reader/burner in this era of usb sticks it’s still nice to have, especially since I’ve got a few installation disks I’d like to use. A small fee that saves time I’d say. Floppies are dead for me though.&lt;/p&gt;
&lt;p&gt;I also wanted it to be quiet and according to some who probably knows better than me by far the biggest noise source is the stock CPU silencer - so I threw down one which looked good. In hindsight it works great too.&lt;/p&gt;
&lt;p&gt;The case looks good and it was also solid, no qualms there. But the one big issue I had was the graphics card, oh how hard it was! I wanted something silent, something from Nvidia (Ati drivers used to suck on linux, but maybe not anymore), something that’s reasonably powerful and also cheap. Not a bad combination I say! I think I chose something reasonably good - the fan is very silent, it’s a good chipset and it wasn’t all too expensive. However I haven’t gotten any games to work with it on linux but that’s probably a configuration issue, annoying anyway.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/das3.jpg&quot; width=&quot;600&quot; /&gt;
&lt;figcaption&gt;Keyboard, Das Keyboard&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The keyboard, oh the keyboard! I got it in my head that I had to have a mechanical keyboard, they’re supposed to be a lot better than the “regular” ones. And oh yeah it’s absolutely wonderful, it’s a joy to type in and I’m already irking when I have to go back typing on another keyboard. But it is a tad too load according to Veronica, and it was oh so &lt;em&gt;expensive&lt;/em&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/overall2.jpg&quot; width=&quot;600&quot; /&gt;
&lt;figcaption&gt;My workspace!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Overall I’m very happy and I don’t think I would’ve done anything different if I were to buy it today, except maybe try an Ati card, some say the drivers aren’t bad at all anymore.&lt;/p&gt;
&lt;p&gt;Finally some more pictures:&lt;/p&gt;
&lt;figure class=&quot;gallery&quot;&gt;
&lt;a href=&quot;/images/inside1.jpg&quot;&gt;&lt;img src=&quot;/images/inside1.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/case.jpg&quot;&gt;&lt;img src=&quot;/images/case.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/cables.jpg&quot;&gt;&lt;img src=&quot;/images/cables.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/inside2.jpg&quot;&gt;&lt;img src=&quot;/images/inside2.jpg&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/das1.jpg&quot;&gt;&lt;img src=&quot;/images/das1.jpg&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
</content></entry><entry><title>Resurrection</title><id>http://jonashietala.se/blog/2011/08/18/resurrection/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/08/18/resurrection" rel="alternate"/><published>2011-08-18T16:28:50+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Aah what a nice summer!&lt;/p&gt;
&lt;p&gt;It was nice to be back in Övertorneå, doing nothing in particular. Just not having to make lunch and dinner every day is such a relief, and if you do slip up food with grandma or Veronica’s parents is only a phone call away. I watched TV, played rollercoaster 2 and simcity 4 and just killed time in front of my beloved (PC).&lt;/p&gt;
&lt;p&gt;The only real work I did was clean the house a time or two and made food for my little brother Filip and did some exercises with him when my parents worked. But it was a pretty small price to pay as my mum helped me invest in a new computer! Of course dad couldn’t find out but that wasn’t so hard - I do live about 1400 km away from home anyway.&lt;/p&gt;
&lt;p&gt;But now things are moving back to the way things were before the summer break; I’m back in Linköping cooking (lunch, dinner &lt;em&gt;and&lt;/em&gt; breakfast), trying to remember watering our plants and generally enjoying life. Everything is almost set for Veronica’s return so I need to take it easy a bit before she storms into my life again tomorrow…&lt;/p&gt;
&lt;p&gt;There’s a lot of stuff I need to reboot again; studying obviously but I also want to make more games and program a bit which I completely neglected the last months and taekwon-do is starting again! My first practice went to hell though, I almost managed to get a blackout as I didn’t drink nearly enough but oh well.&lt;/p&gt;
&lt;p&gt;But the first step is to write a bit more here, I hear that’s a &lt;a href=&quot;http://www.xaprb.com/blog/2011/08/04/computer-science-students-learn-to-write/&quot;&gt;useful skill&lt;/a&gt; to have. Instead of taking a boring class I can just write stuff here I guess.&lt;/p&gt;
</content></entry><entry><title>Ludum Dare 20 Timelapse</title><id>http://jonashietala.se/blog/2011/05/02/ludum_dare_20_timelapse/index.html</id><updated>2024-06-27T07:47:34+00:00</updated><link href="https://www.jonashietala.se/blog/2011/05/02/ludum_dare_20_timelapse" rel="alternate"/><published>2011-05-02T14:14:56+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So this time I managed to compose a timelapse of my weekend and the making of &lt;a href=&quot;/blog/2011/05/02/my_minions/&quot;&gt;My Minions&lt;/a&gt;. Sadly I lost the first few hours as I forgot to turn it on…&lt;/p&gt;
&lt;p&gt;Anyway here’s the result:&lt;/p&gt;
&lt;a href=&quot;https://www.youtube.com/watch?v=ABVPlRaA5iI&quot;&gt;https://www.youtube.com/watch?v=ABVPlRaA5iI&lt;/a&gt;</content></entry><entry><title>I Made It!</title><id>http://jonashietala.se/blog/2011/05/02/i_made_it/index.html</id><updated>2023-10-13T17:18:36+00:00</updated><link href="https://www.jonashietala.se/blog/2011/05/02/i_made_it" rel="alternate"/><published>2011-05-02T02:52:25+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s been over a year, but I haven’t lost (most) my touch yet! For the second time I’ve completed a &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt;! Not an easy feat and yet there are tons of games that look absolutely wonderful. I’m not there yet but now I have at least gotten back into game making again, long overdue.&lt;/p&gt;
&lt;p&gt;I will make a formal post and all that jaz when I wake up tomorrow, or maybe I’ll sleep the whole day… Nah not really, but at least a while.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-20/?action=preview&amp;amp;uid=1895&quot;&gt;Here&lt;/a&gt;’s my entry btw, didn’t turn out the way I wanted it to but in the end I’m quite satisfied. There are a ton of possibilities for it though.&lt;/p&gt;
&lt;p&gt;Oh well. Nap time!&lt;/p&gt;
</content></entry><entry><title>My Minions</title><id>http://jonashietala.se/blog/2011/05/02/my_minions/index.html</id><updated>2026-04-27T11:09:54+00:00</updated><link href="https://www.jonashietala.se/blog/2011/05/02/my_minions" rel="alternate"/><published>2011-05-02T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I think I made it! It became a pretty different game from what I set out to create, but I’m glad with how it turned out.&lt;/p&gt;
&lt;h1&gt;My Minions&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/minion2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/minion3.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/minion1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Instructions&lt;/h1&gt;
&lt;p&gt;Build a pathway and then place objects or release minions on it, everything must be on a path. Place musical objects or make the minions turn or split to make sound and create some music. Or you can create a digital circuit and make it do something fun.&lt;/p&gt;
&lt;h1&gt;Controls&lt;/h1&gt;
&lt;p&gt;Mouse Left - Place an object&lt;br /&gt;
1 - Toggle up through objects&lt;br /&gt;
2 - Toggle down through objects&lt;br /&gt;
Space - Release a minion&lt;br /&gt;
K - Kill all minions&lt;/p&gt;
&lt;p&gt;P - Pause&lt;br /&gt;
Left Shift - Increase speed&lt;br /&gt;
Left Ctrl - Decrease speed&lt;/p&gt;
&lt;p&gt;L - Load map&lt;br /&gt;
S - Save map&lt;/p&gt;
&lt;p&gt;F1 - Console, nothin fun :(&lt;br /&gt;
F10 - Exit the game&lt;/p&gt;
&lt;p&gt;Now beware, I didn’t have the time or energy to create a full blown level saving,
so it will always use “level.dat” in bin as it’s save file. It will overwrite and
it will do so without asking.&lt;/p&gt;
&lt;h1&gt;Source&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/My-Minions&quot;&gt;https://codeberg.org/treeman/My-Minions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you want to build it yourself it depends on: lua, boost and sfml.&lt;/p&gt;
</content></entry><entry><title>Making a Game Again?</title><id>http://jonashietala.se/blog/2011/04/28/making_a_game_again/index.html</id><updated>2026-04-27T11:10:15+00:00</updated><link href="https://www.jonashietala.se/blog/2011/04/28/making_a_game_again" rel="alternate"/><published>2011-04-28T09:16:36+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve gotta do a lab today at school, tomorrow I need to do the exam I missed when I had my glasses-missing headaches and I’m going to Ikea and some other shops for, you guessed it, shopping! Sure it’s fun and sure I need to do these things but the only thing on my mind now is making a new game. This weekend &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare&lt;/a&gt; is on again and I would really, really like to enter it! It’s been &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;over a year&lt;/a&gt; since my last Ludum Dare and almost 11 months since my &lt;a href=&quot;/blog/2010/06/06/wheres_teddy/&quot;&gt;last game&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I want to make games again..&lt;/p&gt;
&lt;p&gt;I can’t promise a new game this weekend but I think I might have the time for some game creation on friday, saturday and sunday evening/night so I just might. The last time I even had a massage course the whole day on sunday/saturday so I should be fine.&lt;/p&gt;
&lt;p&gt;This time I also think I can come up with some more sound and music compared to the last time (where I only had two thuds!). I got &lt;a href=&quot;http://lmms.sourceforge.net/&quot;&gt;LMMS&lt;/a&gt;, a free music creation program. I really suck at making music though lol.&lt;/p&gt;
&lt;p&gt;I haven’t made a game since I switched to Slackware either, luckily &lt;a href=&quot;http://www.sfml-dev.org/&quot;&gt;SFML&lt;/a&gt; is cross platform. I’ve also got my old &lt;a href=&quot;https://codeberg.org/treeman/7days&quot;&gt;7days library&lt;/a&gt;, my collection of old game creating codebase which I was pretty proud of for a while.&lt;/p&gt;
&lt;p&gt;For graphics I think I’m aiming for some pixelated cool stuff with &lt;a href=&quot;http://mtpaint.sourceforge.net/&quot;&gt;mtPaint&lt;/a&gt;. Pixelated stuff looks awesome, if you’re good at it, and I’d like to make something similar.. At least a little similar.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/koncept.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;So for a quick recap, if I’m going to make a game again this is what I’m going to use:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://lmms.sourceforge.net/&quot;&gt;LMMS&lt;/a&gt; for music&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sfml-dev.org/&quot;&gt;SFML&lt;/a&gt; as the core game library (graphics, sound and input)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codeberg.org/treeman/7days&quot;&gt;7days library&lt;/a&gt; for useful stuff&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mtpaint.sourceforge.net/&quot;&gt;mtPaint&lt;/a&gt; for pixel graphics&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As usual it’ll be made in C++ (I might do something else another time) and I’ll probably listen to &lt;em&gt;Raubtier, Sarah Brightman, Hans Zimmer&lt;/em&gt; and some classical composers &lt;em&gt;(Mozart, Bach, Vivaldi etc)&lt;/em&gt;.&lt;/p&gt;
</content></entry><entry><title>What&apos;s up</title><id>http://jonashietala.se/blog/2011/04/22/whats_up/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/04/22/whats_up" rel="alternate"/><published>2011-04-22T10:55:24+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s been a while again since the last time we met mr. Blog. I’ve been busy with school and other stuff. I’ve thought about you but I just never really picked up emacs to write to you. I know it’s my fault but I beg of your mercy mr. Blog. &lt;a href=&quot;/blog/2011/02/09/a_week_of_headache&quot;&gt;You know&lt;/a&gt; that I had laid off school for a bit but now I’ve caught up with almost everything. I’ve got a bit of electronics left: 2 labs and one project assignment. It’s a pretty damn hard course but now when I’ve taken my time to sit down and go through everything it’s quite fun! It’s also a course over the whole semester so it’s not even done yet. The other thing I’m behind in is math. I chose not to do the last exam, so I can do it now in about a week.&lt;/p&gt;
&lt;p&gt;I’m home in Övertorneå again and it’s fairly chill here. It’s pretty nice to eat food someone else has made, and I don’t have to think about holding the apartment afloat. Admittedly Veronica is a &lt;em&gt;great&lt;/em&gt; help (I might actually be the help).&lt;/p&gt;
&lt;p&gt;I’ve been meaning to program a bit but I’ve only done it a little, I’ve been watching starcraft and just chillin’ for the main part.&lt;/p&gt;
&lt;p&gt;I’ll be sure to update a bit better for you mr. Blog.&lt;/p&gt;
</content></entry><entry><title>A Four-Eyed Update</title><id>http://jonashietala.se/blog/2011/03/21/a_four-eyed_update/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/03/21/a_four-eyed_update" rel="alternate"/><published>2011-03-21T12:25:58+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Wow it’s been a while! Almost a month and a half since my &lt;a href=&quot;/blog/2011/02/09/a_week_of_headache&quot;&gt;last update&lt;/a&gt;. There I complained about my almost constant headaches which hampered me a lot actually. Luckily now I have joined the rank of cool.&lt;/p&gt;
&lt;p&gt;I took home three frames I think and tried them out and I settled some I thought were fairly good looking, nothing special mind you but at least they didn’t look horrible on me. Then I went back and I settled on the semi-expensive ones and then I waited. And waited. Then I went back and asked but the glasses didn’t fit into the price class I’d chosen, something about the frames being too bent, so I had to pay some more.&lt;/p&gt;
&lt;p&gt;Then I waited again, and a little bit more… until I called once more, now I was getting pretty pissed, but they should be here this Friday. They called on Thursday and finally I had them! It’s funny, I was going to demand some discount but even the pricier glasses didn’t fit and so I got some really expensive ones. Fair enough I thought and so I left.&lt;/p&gt;
&lt;p&gt;The first few days were pretty disoriented, but man oh man what a difference. It’s funny how you don’t realize how bad your sight is before you get a pair of glasses and that really fit me well. Suddenly I didn’t have to stick my nose into the screen to see the text and today I was at school the whole day! Sure I’m a bit lazy sometimes but I also couldn’t concentrate like this before.&lt;/p&gt;
&lt;p&gt;Life is good.&lt;/p&gt;
</content></entry><entry><title>A Week of Headache</title><id>http://jonashietala.se/blog/2011/02/09/a_week_of_headache/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/02/09/a_week_of_headache" rel="alternate"/><published>2011-02-09T18:00:46+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This was supposed to be a productive week with lots and lots of Perl and Ada but instead I’ve had this big headache all week, and some the week before and it’s gotten pretty bad so I can’t really concentrate on anything really. The electronics assignment was a bitch and it took a looong time to complete, even if all I had to do was to rewrite some stuff. You just love when the result is completely wrong just thanks to a misplaced minus sign.&lt;/p&gt;
&lt;p&gt;So now I’m a bit worried, luckily not as much as my girlfriend, and what’s the cause of this? The lack of water is probably the source of 90% of my headaches but now when I drink and drink it only eases of a bit and then it’s back. Painkillers help a bit but I don’t want to turn into a junkie just to be able to act normally.&lt;/p&gt;
&lt;p&gt;Luckily I think I’ve found the reason, but sadly it’s not the very best one. I think I need glasses. I squint &lt;em&gt;all the time&lt;/em&gt; in front of the computer and I’m getting headaches when I’m reading. So this Friday it’s judgement day. I dunno what I’m hoping for, if it’s glasses then fine at least it should be better, but if it’s not then it might be a bigger problem somewhere.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;http://3.bp.blogspot.com/_W8MKyrpvUV4/TGwi8kA2tVI/AAAAAAAAAVQ/59FGbUhfYtM/s1600/20071128geek.jpg&quot; /&gt;
&lt;figcaption&gt;Me of tomorrow?&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>The Little Things in Life</title><id>http://jonashietala.se/blog/2011/02/03/the_little_things_in_life/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/02/03/the_little_things_in_life" rel="alternate"/><published>2011-02-03T21:32:10+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s the little things in life that makes it extra special. Sometimes it’s the luxury of coffee together with the morning paper and other times it’s just a small simple smile from a random stranger, kid or dog. Today when I got this bad headache I got saved by a two hour nap and my &lt;a href=&quot;http://www.prisjakt.nu/bok.php?p=6960&quot;&gt;Programming in Ada&lt;/a&gt; book. It was quite a pleasure to just read it and not worrying about anything else. I even think my headache disappeared a while there.&lt;/p&gt;
&lt;p&gt;And if that wasn’t enough, my long lost &lt;a href=&quot;http://www.onyxneon.com/books/modern_perl/index.html&quot;&gt;Modern Perl&lt;/a&gt; is finally here! I’ve skimmed a little and boy I think I’m going to like this one. I’m soon up to two digits with my programming books and I really do like them. Even if I’m not doing anything in that particular language it’s still fun to just read about. There’s always something you’ll learn and even if not I still find it soothing.&lt;/p&gt;
&lt;p&gt;Reading books, threads, blog posts or random forum rants/wars about programming is sometimes coffee for my brain (I don’t actually drink coffee or anything with caffeine. I’m almost feeling like an endangered programming species).&lt;/p&gt;
&lt;p&gt;If the book is actually worth reading we’ll see and I’ll report back when I’ve gone through it.&lt;/p&gt;
</content></entry><entry><title>Focusing Attention: Programming</title><id>http://jonashietala.se/blog/2011/01/30/focusing_attention_programming/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/30/focusing_attention_programming" rel="alternate"/><published>2011-01-30T20:33:44+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;These last two weeks have been a small attempt at clearing up my head a bit. I have far too many things I’d like to do and even if it’s not possible to do them all at once it didn’t stop me from thinking of them. One minute it’s that and the other it’s something completely different. This is really not good as it messes with the &lt;a href=&quot;/blog/2011/01/14/the_top_idea&quot;&gt;top idea&lt;/a&gt; a lot so I decided to do something about it. By focusing on &lt;a href=&quot;/blog/tags/attention&quot;&gt;one single thing each week&lt;/a&gt; I’ve been trying to remedy the situation.&lt;/p&gt;
&lt;p&gt;Now I haven’t really spent a lot of time with the things I’ve been focusing on, but I’ve been a whole lot calmer and not as stressed up as before. So I think it’s good for me.&lt;/p&gt;
&lt;p&gt;This week I’m gonna focus on something I haven’t really done so much, namely programming. The little I’ve done is some stuff for school and it’s fun and all, but it’s not really the same as working on your own project. Now I think I’ll try to complete the assignments for the course, but that’s not really a priority and if it’s even a little bit stressful then I’ll cut back on it. We’ve got plenty of time left and it’s not worth it to get stressed by something like that.&lt;/p&gt;
&lt;p&gt;No I’ll focus on Perl (my new Perl book should arrive this week) and making something fun: an IRC-bot. A simple bot isn’t much of a challange so I need to add some cool functions to it. I’m really annoyed that a friend of mine is &lt;em&gt;always&lt;/em&gt; ahead of the latest manga releases so I think I’ll automate that one. I’ve actually already made one in both Perl and lua, but they’re pretty damn bad so this time I’ll make it right. Naturally I’ve got a ton of other stuff to add but we’ll see where we end up.&lt;/p&gt;
&lt;p&gt;The point isn’t to make a bot with a million features, but to start hacking on something fun. Hell I’d be happy if I just stick to the new book and learn Perl a bit.&lt;/p&gt;
</content></entry><entry><title>Poking at Emacs</title><id>http://jonashietala.se/blog/2011/01/30/poking_at_emacs/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/30/poking_at_emacs" rel="alternate"/><published>2011-01-30T19:19:03+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been a vim &lt;a href=&quot;http://www.vim.org/&quot;&gt;vim&lt;/a&gt; fan for a while now and with some &lt;a href=&quot;https://github.com/treeman/dotfiles/blob/c6bb8c790303367286a34744004f2032de996bc0/.vimrc&quot;&gt;recent configs&lt;/a&gt; I’m starting to feel pretty confident and happy with it. For those who don’t know it’s basically a text editor, like notepad, but with a lot of keycommands which allows you to edit code (and text in general) faster. For writing a simple straight up text it might not be worth it, the learning curve is pretty steep, but for someone who codes a lot it’s really good in the long run. &lt;a href=&quot;http://www.viemu.com/a-why-vi-vim.html&quot;&gt;Here’s&lt;/a&gt; an article I read when I read when I started with vim.&lt;/p&gt;
&lt;p&gt;The thing is that I need to work at school too and everyone there use emacs. Emacs is in many ways similar to vim, but they’re a bit like &lt;a href=&quot;http://en.wikipedia.org/wiki/Editor_war&quot;&gt;bitter competitors&lt;/a&gt; and if you’re a vim user, like me, then you’re not an emacs user and vice versa. Also I haven’t gotten vim to work as I want to at school, meaning it doesn’t work &lt;em&gt;exactly&lt;/em&gt; like I’m used to (I’m quite picky with that). So what I’ve done up until now is that I’ve been working from home and trying to avoid emacs as much as humanly possible.&lt;/p&gt;
&lt;p&gt;It’s been working okay so far, but I don’t think it will for much longer. When we’re declaring our labs our teachers use emacs, when I need to collaborate with other students then they most likely will be using emacs and when we have our exam. It was pretty ridiculous yesterday when we had to show our lab and I got really, really nervous on how to open multiple files in emacs… It feels like something I should be able to do in my sleep and if there’s anything like a nerd ranking somewhere I think I just hit rock bottom.&lt;/p&gt;
&lt;p&gt;No this shouldn’t be allowed to continue so now I’m going to give emacs a try. I doubt that it’ll replace vim but still I think it’s quite nice. In theory it should be just as nice as vim, with really fast code editing once you get used to it. &lt;a href=&quot;http://www.io.com/~dierdorf/emacsvi.html&quot;&gt;Here’s a better comparison&lt;/a&gt; of the two. I guess I just don’t like the idea of having to climb another intimidating learning curve.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://i.stack.imgur.com/7Cu9Z.jpg&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;I’ve used notepad, visual studio and vim. Emacs seems though.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>Focusing Attention: Study Hacking</title><id>http://jonashietala.se/blog/2011/01/26/focusing_attention_study_hacking/index.html</id><updated>2023-10-01T09:02:31+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/26/focusing_attention_study_hacking" rel="alternate"/><published>2011-01-26T00:26:45+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A week of drawing is over, but I didn’t draw that much. It was a little bit of a fail from my part.&lt;/p&gt;
&lt;p&gt;But the past is the past and this week I’m going to be study focused. Not that I need to study, but I really need to rework my study technique. I’ve been going on like a classical student, in the bad sense, by skipping class and getting super stressed when the tests and deadlines are over me. Somehow you manage with some last-minute studying and all is well.&lt;/p&gt;
&lt;p&gt;Well not really. I already have a bad stomach and stress makes it a lot worse. Even if I didn’t have this problem stress is never good, especially not when you &lt;em&gt;need&lt;/em&gt; to take this test or finish this assignment &lt;em&gt;for tomorrow&lt;/em&gt;. It screws with my health, my study results and it intrudes on my free time far too much I’d say.&lt;/p&gt;
&lt;p&gt;This is when I dusted an old bookmark I found a long time ago: &lt;a href=&quot;http://calnewport.com/blog/&quot;&gt;Study Hacks&lt;/a&gt;. It’s some guy who writes about studying and study technique and he’s got &lt;a href=&quot;http://calnewport.com/blog/2008/04/18/how-to-become-a-zen-valedictorian-decreasing-your-stress-without-decreasing-your-ambition/&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;http://calnewport.com/blog/2009/03/09/the-straight-a-method-how-to-ace-college-courses/&quot;&gt;pretty&lt;/a&gt; &lt;a href=&quot;http://calnewport.com/blog/2010/09/27/how-double-majors-can-ruin-your-life-two-arguments-for-doing-less/&quot;&gt;good&lt;/a&gt; &lt;a href=&quot;http://calnewport.com/blog/2009/03/27/what-the-hell-is-study-hacks/&quot;&gt;ideas&lt;/a&gt;. This is what I’ll focus on this week: to change my routines and take control over my studies and don’t let them control me.&lt;/p&gt;
&lt;p&gt;Here’s a little rundown of the main principles from &lt;a href=&quot;http://calnewport.com/blog/&quot;&gt;Study Hacks&lt;/a&gt; as I understand them;&lt;/p&gt;
&lt;h1&gt;Do fewer things&lt;/h1&gt;
&lt;p&gt;Sure it makes sense. When I signed up for an extra course last year I felt pretty damn stressed and I couldn’t really focus on my other courses knowing I had this extra class I missed to catch up with. It was even on my mind when I tried to do other things and when I got my stumach problems I decided to drop it. That was seriously a pretty damn good decision: I felt a lot better with it gone.&lt;/p&gt;
&lt;h1&gt;Do them better&lt;/h1&gt;
&lt;p&gt;Also what are good grades? They should show your skill but if they’re good they should also impress. And what are you most impressed by? Someone with straight-A or someone who’s read 40 points more but with slightly worse grades? I think we’re more impressed by deep knowledge in a smaller area (better grades in fewer courses) than by someone who’s a know-it-all but specialist-in-nothing. Maybe it’s a good idea to focus on getting really good grades instead of trying to do too much at once and risk to spread out too much?&lt;/p&gt;
&lt;h1&gt;Know why you’re doing them&lt;/h1&gt;
&lt;p&gt;Lastly it makes sense why you should know why your study technique works (or doesn’t). So we can change and adapt. After all what is the definition of Insanity?&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Doing the same thing over and over again expecting different results&lt;/p&gt;
&lt;footer&gt;&lt;span class=&quot;author&quot;&gt;Albert Einstein&lt;/span&gt;&lt;/footer&gt;
&lt;/blockquote&gt;</content></entry><entry><title>The I&apos;m Great quote</title><id>http://jonashietala.se/blog/2011/01/19/the_im_great_quote/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/19/the_im_great_quote" rel="alternate"/><published>2011-01-19T23:45:03+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;A new semester at the uni and so far it looks promising; I got a hold of some new books even though the bookstore had a snakelike queue similar to the &lt;a href=&quot;http://en.wikipedia.org/wiki/J%C3%B6rmungandr&quot;&gt;Jörmungandr&lt;/a&gt; (the snake that encircled the earth in nordic mythology) and our new programming course started. This time it’s Ada’s turn and as always it should be interesting. At a first glance it doesn’t look like it’s introducing anything completely new from what I’m used with. I guess it looks like a cross between C and Haskell’s type system spiced up with some other stuff.&lt;/p&gt;
&lt;p&gt;It’s funny how I notice all these little, syntactic similarities (haven’t done anything real with the language yet so I’m a bit shallow now but whatever) from different languages. It was a long time ago I came across a language that distinguish between functions and subroutines. I think that was the case with Visual Basic, my oh so dear first language a few years ago. Might’ve been five years ago?&lt;/p&gt;
&lt;p&gt;Anyway quite enough of that, I don’t want to derail too much. What I really wanted to write about is when our new teacher, who by the way is completely awesome, asked us who thought they were a great programmer. Most of us laughed it off but I think there were two, maybe three, who raised their hands.&lt;/p&gt;
&lt;p&gt;I thought about raising my hand, but who do I think are great programmers? &lt;a href=&quot;http://en.wikipedia.org/wiki/Donald_Knuth&quot;&gt;Knuth&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Linus_Torvalds&quot;&gt;Thorvalds&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Djikstra&quot;&gt;Djikstra&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Bjarne_Stroustrup&quot;&gt;Stroustrup&lt;/a&gt; &lt;a href=&quot;http://en.wikipedia.org/wiki/Ken_Silverman&quot;&gt;Silverman&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/John_carmack&quot;&gt;Carmack&lt;/a&gt; comes to mind. They’re probably not the greatest, but they’ve done some really notable things. Do I think I’m at their level? What a laugable question, I’m &lt;em&gt;miles&lt;/em&gt; away. And I’m sure there’s some &lt;a href=&quot;http://www.codethinked.com/post/2007/12/06/The-Programmer-Dress-Code.aspx&quot;&gt;epic bearded fellow&lt;/a&gt; somewhere out there who’s even higher on the programming skill ladder.&lt;/p&gt;
&lt;p&gt;Now what is a great programmer then? I have no idea. But I do know that with all the things I don’t know, I couldn’t be one. Sure I’ve done something in about 10 different (some not so different) languages. But there are &lt;a href=&quot;http://en.wikipedia.org/wiki/List_of_programming_languages&quot;&gt;hundreds more&lt;/a&gt;. I’ve done nothing low level, I have no experience with op codes or assembly and I’m not up to date with the latest scripting languages. There are a few new interesting languages like &lt;a href=&quot;https://github.com/graydon/rust/wiki/&quot;&gt;Rust&lt;/a&gt;, &lt;a href=&quot;http://jashkenas.github.com/coffee-script/&quot;&gt;CoffeeScript&lt;/a&gt; or &lt;a href=&quot;http://golang.org/&quot;&gt;Go&lt;/a&gt; which I haven’t even looked at yet. Of course the number of languages you know doesn’t make you great, but it just feels like I’m missing stuff.&lt;/p&gt;
&lt;p&gt;Sure these guys could be great - who am I to say otherwise? But you’ll have to wait a long time for me to spill the I’m great quote. Hell, maybe even a lifetime?&lt;/p&gt;
</content></entry><entry><title>Focusing Attention: Drawing</title><id>http://jonashietala.se/blog/2011/01/17/focusing_attention_drawing/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/17/focusing_attention_drawing" rel="alternate"/><published>2011-01-17T12:49:52+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;In my &lt;a href=&quot;/blog/2011/01/14/the_top_idea&quot;&gt;last post&lt;/a&gt; I wrote about some ideas and projects I have and how it’s a little bit too much at a time, so now I’m going to try something new here. In the beginning of every week I’ll declare something I’ll be focusing on and then that’s the only thing I should focus on on my free time. Just so I don’t drift off from irc bots in haskell to opening a new Erlang book or starting a game and then move on with another.&lt;/p&gt;
&lt;p&gt;Not really so I don’t work on several things at once but so I don’t think about the other things too much.&lt;/p&gt;
&lt;p&gt;This week I think I’ll be focusing on &lt;em&gt;drawing&lt;/em&gt;. I kinda like to draw and I drew a lot when I was little but then it wore off a bit, I dunno why. I think I was pretty good too, well I didn’t think so then but when I look back at the drawings I’m sure I at least had something going for me.&lt;/p&gt;
&lt;p&gt;Recently I bought the book &lt;a href=&quot;http://www.drawright.com/&quot;&gt;Drawing on the Right Side of the Brain&lt;/a&gt; - I’m not really sure why but so far it’s been pretty darn good. Hopefully I’ll have some progress, but I’m sure I’ll have fun whether it’s a success or not.&lt;/p&gt;
&lt;p&gt;Of course there are &lt;a href=&quot;http://theportraitart.com/&quot;&gt;some amazing stuff around&lt;/a&gt; and if I could get a tenth or even one percentage of his skill it’d be cool has hell!&lt;/p&gt;
</content></entry><entry><title>The Top Idea</title><id>http://jonashietala.se/blog/2011/01/14/the_top_idea/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/14/the_top_idea" rel="alternate"/><published>2011-01-14T10:05:25+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Recently I’ve been having a dozen ideas and projects I’ve been poking around with:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I wrote a simple lua, later perl, which announced when a new &lt;a href=&quot;https://day9.tv/&quot;&gt;day9&lt;/a&gt; episode has come. Later I expanded it to search for new manga episodes, but now it’s broken and unfinished.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In an attempt to learn Haskell I began writing a simple irc bot, but I never did come far with the language and now I’m a bit stuck. I have the bot itself working but I want to restructure it with plugins instead of hardcoding every command and I’d like to have some interactivity like saving state and fetching info from internet. But I haven’t come that far and now it’s on a stand-still.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Totally not related to the other two I want to learn how to draw. On a little whim I bought the book &lt;a href=&quot;http://www.drawright.com/&quot;&gt;Drawing on the Right Side of the Brain&lt;/a&gt; and I was totally blown away. I was a bit sceptic at first but she’s explaining everything so scientifically and &lt;a href=&quot;http://drawright.com/gallery.htm&quot;&gt;the results look amazing&lt;/a&gt;. Almost too good to be true. But as always I started but I’m not there yet, in fact a pretty long way from finished.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Back to the programming business. I’d like to update the backend of this site, but to be fair it’s not &lt;em&gt;that&lt;/em&gt; important. Just something that’d be nice to do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What’s worse is my game projects. What projects you ask? Well I started a few much bigger games this time and they have just faded away from my brain little by little and now I’m not that into them. I mean the ideas are amazing, but I haven’t done anything with them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The issue here I think is that I’m trying to do far too many things at once. Back when I wrote all my &lt;a href=&quot;/blog/2010/03/30/the_experimental_games&quot;&gt;experimental games&lt;/a&gt; I didn’t have these many things going on. In fact they were the &lt;em&gt;only&lt;/em&gt; thing on my mind - you know the thing you think about when you’re in the shower or before you go to sleep. Hell I’ve even woken up, all sweaty, and had a solution but the very problem I had struggled all day with!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://paulgraham.com/&quot;&gt;Paul Graham&lt;/a&gt; wrote a &lt;a href=&quot;http://www.paulgraham.com/top.html&quot;&gt;nice article&lt;/a&gt; about this a while ago. He’s more focused on startups of course but the core of the article very much applies to me. I’m not keeping the right idea on the top of my mind, instead I think it’s changing - I’m doing too many things at once. One time I’m focused on say learning Haskell but the next day, or even the very same night I’m all wound up about a game I’d like to make! How will I ever get things done if I’m floating around like that?&lt;/p&gt;
&lt;p&gt;Of course Paul points out that I’m in good company, even Newton fell into this trap and I have a feeling many more have this problem.&lt;/p&gt;
</content></entry><entry><title>2010 in review</title><id>http://jonashietala.se/blog/2011/01/06/2010_in_review/index.html</id><updated>2023-10-01T08:59:58+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/06/2010_in_review" rel="alternate"/><published>2011-01-06T00:13:06+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I saw a &lt;a href=&quot;http://briancarper.net/blog/574/2010-in-review&quot;&gt;post on briancarper&lt;/a&gt; where he reviews the past year and it sounds like a great idea actually.&lt;/p&gt;
&lt;h1&gt;2010 Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Wrote a few games earlier this year;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2010/01/16/the_chronicles_of_bim_the_100_fake_afros/&quot;&gt;The Chronicles of Bim: The 100 Fake Afros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2010/02/28/a_geek_valentine/&quot;&gt;A Geek Valentine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2010/04/26/beebop_the_island_hopper/&quot;&gt;Beebop The Island Hopper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2010/06/06/wheres_teddy/&quot;&gt;Where’s Teddy?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Updated this site a bit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the process I learned a lot of PHP, Javascript, mysql and design. Fun and useful.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switched to &lt;a href=&quot;http://www.slackware.com&quot;&gt;Slackware&lt;/a&gt; which I like a &lt;em&gt;ton&lt;/em&gt; better than Ubuntu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned a lot more linux. Thanks Slackware.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned a lot more &lt;a href=&quot;http://git-scm.com/&quot;&gt;git&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned a lot more &lt;a href=&quot;http://www.vim.org/&quot;&gt;vim&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tried out and configured &lt;a href=&quot;http://www.uzbl.org&quot;&gt;uzbl&lt;/a&gt; which I still use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned a bit of Haskell.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tried out Perl a bit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learned a lot more Lisp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switched to zsh. It’s fine after a bit of config&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rebuilt a custom Kernel a few times, some failures but learned a lot.  And got starcraft 2 to work!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read a lot. This years high were One Piece and Jeffery Deaver. Real World Haskell scores the highest Geek score.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2010 Non-Geek Achievements&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Moved to Linköping with my girlfriend Veronica and I didn’t just survive but I also liked it!&lt;/li&gt;
&lt;li&gt;Enrolled in a Linköpings University in Computer Science. We’ll see if it’ll get geeky later, atm it’s a breeze but we have a ton of seemingly fun courses to go.&lt;/li&gt;
&lt;li&gt;Took a massage course.&lt;/li&gt;
&lt;li&gt;Learned how to cook more than one dish.&lt;/li&gt;
&lt;li&gt;Did the dishes, expertly maneuvered our vacuum cleaner and did the laundry. &lt;em&gt;More than once!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Started Taekwondo and after a few months of hard work I even got a yellow stripe for my white belt!&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2010 Failures&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Didn’t produce enough games.&lt;/li&gt;
&lt;li&gt;Didn’t write enough code.&lt;/li&gt;
&lt;li&gt;Got worse in my stumach towards the end of the year. Too stressed and not enough regular meals I guess.&lt;/li&gt;
&lt;li&gt;Didn’t blog enough. Sorry :(&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Plans for 2011&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Get good results in school.&lt;/li&gt;
&lt;li&gt;Make more games.&lt;/li&gt;
&lt;li&gt;Code more!&lt;/li&gt;
&lt;li&gt;Blog more!&lt;/li&gt;
&lt;li&gt;Learn more Haskell (again). This time continue with the small irc bot I’m writing.&lt;/li&gt;
&lt;li&gt;Learn a few more languages and expand my knowledge. Maybe some low level stuff with C or assembly? Or some more higher level?&lt;/li&gt;
&lt;li&gt;Get a better sense of algorithms.&lt;/li&gt;
&lt;li&gt;Try to be a bit more social&lt;/li&gt;
&lt;li&gt;Get a new belt in Taekwondo.&lt;/li&gt;
&lt;li&gt;Be a bit more disciplined with training, coding and school.&lt;/li&gt;
&lt;li&gt;Loosen up a bit more so the stumach won’t mess anymore.&lt;/li&gt;
&lt;li&gt;Last but not least, keep Veronica happy and help around at home.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I thought I didn’t do anything this year I guess it’s been a productive year anyway. But in 2011 I think I’ll do a lot more still.&lt;/p&gt;
</content></entry><entry><title>My Dream Game: The Tycoon</title><id>http://jonashietala.se/blog/2011/01/05/my_dream_game_the_tycoon/index.html</id><updated>2023-10-01T08:59:33+00:00</updated><link href="https://www.jonashietala.se/blog/2011/01/05/my_dream_game_the_tycoon" rel="alternate"/><published>2011-01-05T13:55:12+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve been playing &lt;a href=&quot;http://eu.battle.net/sc2/en/&quot;&gt;Starcraft 2&lt;/a&gt; a little this christmas. It wasn’t dead serious 1v1 which really is my favorite but I’ve played 2v2 with some friends and I actually played the campaign a bit and it was pretty fun! Usually I never play the campaign on RTS games but this one I liked. I even bought it to my little brother and he seems to like it.&lt;/p&gt;
&lt;p&gt;But it’s funny - yesterday when I went down to check on him he was playing &lt;em&gt;Rollercoaster Tycoon 3&lt;/em&gt;!&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://cdn.akamai.steamstatic.com/steam/apps/1368820/ss_569d87da325a5b814346cd5c7255ace94e0fa40f.600x338.jpg?t=1667400683&quot; title=&quot;Rollercoaster Tycoon 3&quot; /&gt;
&lt;figcaption&gt;Illustration of Rollercoaster Tycoon 3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One of my absolute favourite games (the whole series in fact) and that got me all nostalgic again. Tycoon games are so good; &lt;em&gt;SimCity&lt;/em&gt;, &lt;em&gt;Theme Hospital&lt;/em&gt;, &lt;em&gt;Rollercoaster Tycoon&lt;/em&gt;, &lt;em&gt;Evil Genius&lt;/em&gt; and more! I’m not surprised to see him playing this old game, I replay these games myself from time to time. I’m almost through &lt;em&gt;Theme Hospital&lt;/em&gt; for the fifth time or something. You just don’t seem to get tired of them you know.&lt;/p&gt;
&lt;p&gt;Of course I’d like to make my own tycoon game. Not entirely unlike &lt;a href=&quot;/blog/2009/11/25/jonas_icecream_stand/&quot;&gt;Jonas IceCream Stand&lt;/a&gt; but with actual building of course. I wonder how it’d look like though.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;evil genius’ traps/base planning + rollercoasters + theme hospital’s hilarity + simcity’s economy = ?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The best of the best games should make something good. That’s only a theory though…&lt;/p&gt;
</content></entry><entry><title>Christmas break</title><id>http://jonashietala.se/blog/2010/12/18/christmas_break/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/12/18/christmas_break" rel="alternate"/><published>2010-12-18T22:35:43+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So school is on a break and I welcome it with all of my heart. The semester has been pretty fun and I really enjoy studying here. We had &lt;a href=&quot;http://en.wikipedia.org/wiki/Lisp_(programming_language)&quot;&gt;lisp&lt;/a&gt; the whole time which is a pretty sweet little language and if you haven’t, give it a shot. Then we had math and I do like math, although I wasn’t really motivated this time around and I dunno why. Maybe because I think I got it pretty fast and that didn’t really motivate me to study when the test came around and I got far too many dumb mistakes I think.. Not good, not good.&lt;/p&gt;
&lt;p&gt;Speaking about math then I took an extra course, mathematical statistics or something funky like that but meh it wasn’t all I thought it’d be. In fact it was almost a bit boring and when I got problems with my stumach again (dunno why, but I think it has to do with stress or my irregular eating patterns, or both) so I kinda dropped it. But nothing’s really missed: we’re gonna have something similar later on anyway.&lt;/p&gt;
&lt;p&gt;Now I haven’t made anything game related in a while which sucks. A month ago or something I was poking at some prototype but it hasn’t gotten anywhere yet. I was going to enter &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;ludum dare 19&lt;/a&gt; but then I kinda just didn’t, and now it’s too late to do anything. And I have like a thousand ideas I’d like to do, but I don’t seem to have done anything.&lt;/p&gt;
&lt;p&gt;Argh!&lt;/p&gt;
&lt;p&gt;And then there’s my other programming interests of course. I’ve been poking at Haskell a few months ago but now I actually want to &lt;em&gt;learn&lt;/em&gt; the damn language and the best way to do that is to make something real from scratch, so I’ve started my own (atm extremely simple) irc bot. Then I’ve bought the classical K&amp;amp;R C book and some book about Erlang and I’d like to get going with those too.&lt;/p&gt;
&lt;p&gt;Add to that we’re gonna do Ada in school after christmas which could be pretty darn fun too. There’s surely not a shortage of stuff to at least!&lt;/p&gt;
</content></entry><entry><title>Going to University</title><id>http://jonashietala.se/blog/2010/10/06/going_to_university/index.html</id><updated>2023-10-01T08:57:58+00:00</updated><link href="https://www.jonashietala.se/blog/2010/10/06/going_to_university" rel="alternate"/><published>2010-10-06T09:16:54+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I mentioned in the last post that I’m going to the university, which might explain my lack of activity here and for that I’m sorry. It’s not as hard as I had imagined, and I don’t have that much in school but there’s still a lot that’s going on. For example now how to make something which doesn’t focus on pasta or meatballs and I’ve also done the laundry a few times. These are all thanks to my girlfriend and without her I doubt that I would eat anything other than pasta and I would constantly wake up just to find that I don’t have any clean underwear left.&lt;/p&gt;
&lt;p&gt;There are still a few homework things I need to do from time to time, but those are often either math or lisp which are pretty fun so no harm has been done to me yet.&lt;/p&gt;
&lt;p&gt;I should really begin with the game making again now when my schedual is opening up a bit.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/gents.jpg&quot; /&gt;
&lt;figcaption&gt;A secret preview of my latest game project.&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>The great Hochstapler</title><id>http://jonashietala.se/blog/2010/09/19/the_great_hochstapler/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/09/19/the_great_hochstapler" rel="alternate"/><published>2010-09-19T11:17:32+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Hey there. A lot has happened lately since my last update and my last game here.&lt;/p&gt;
&lt;p&gt;I’m now a pretty happy student at Linköpings university and I’m reading something similar to Computer Science or Computer engineering, but I guess it’ll become whatever you make it to be. For starters we’re reading a bit math and a bit common lisp, which is fun but hopefully this is just the beginning.&lt;/p&gt;
&lt;p&gt;Me and Veronica are now living in a fairly nice apartment and I think I’ve increased my cooking skills a few magnitudes since I got here. Admittedly that’s not a too big of an accomplishment…&lt;/p&gt;
&lt;p&gt;I haven’t had any time, or energy, to focus on game development. There are a few things I’d like to do but we’ll see what happens. My friend on the other hand has been productive and he has just finished one of his big game projects: &lt;a href=&quot;http://gridlockgames.net/games.html#hochstapler&quot;&gt;Hochstapler&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;http://gridlockgames.net/bilder/games/hochstapler1.png&quot; /&gt;
&lt;figcaption&gt;Hochstapler, the epic production from Gridlock Games&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It’s a really fun game with some inspiration from the old commodore and I really recommend you to give it a try. The only downside is of course that I just can’t beat his highscore!&lt;/p&gt;
</content></entry><entry><title>Where&apos;s Teddy?</title><id>http://jonashietala.se/blog/2010/06/06/wheres_teddy/index.html</id><updated>2026-04-27T11:09:47+00:00</updated><link href="https://www.jonashietala.se/blog/2010/06/06/wheres_teddy" rel="alternate"/><published>2010-06-06T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I did this course Game Design and what’s a course on Game Design without a game? Well, here it is. Made in about seven days (more likely eight) and I thought it became quite cool.&lt;/p&gt;
&lt;h1&gt;Where’s Teddy?&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/teddy1.png&quot; alt=&quot;&quot; /&gt;  &lt;img src=&quot;/images/games/thumbs/teddy2.png&quot; alt=&quot;&quot; /&gt;  &lt;img src=&quot;/images/games/thumbs/teddy3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;How to Play&lt;/h1&gt;
&lt;p&gt;Your mission is to find teddy and his teddybear friends. The problem is that it’s dark and it’s really hard to find them if you can’t see where you’re going but thankfully you have a candle with you and if you’re lucky you can stumble on more candles to keep you from going completely dark.&lt;/p&gt;
&lt;h1&gt;Controls&lt;/h1&gt;
&lt;p&gt;Move with &lt;em&gt;Arrow Keys&lt;/em&gt;&lt;br /&gt;
Switch and light candles with &lt;em&gt;Space&lt;/em&gt;&lt;br /&gt;
Next Level: &lt;em&gt;N&lt;/em&gt;&lt;br /&gt;
Previous Level: &lt;em&gt;P&lt;/em&gt;&lt;br /&gt;
Reset Level: &lt;em&gt;R&lt;/em&gt;&lt;br /&gt;
Console: &lt;em&gt;F1&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Sound effects:&lt;/em&gt; Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Music:&lt;/em&gt; Joshua Holtz - Sounds of Insects&lt;br /&gt;
&lt;em&gt;Rest:&lt;/em&gt; Me&lt;/p&gt;
&lt;h1&gt;Source&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/Wheres-Teddy&quot;&gt;https://codeberg.org/treeman/Wheres-Teddy&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>Game Design Analysis: World of Goo</title><id>http://jonashietala.se/blog/2010/06/01/game_design_analysis_world_of_goo/index.html</id><updated>2024-09-11T08:17:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/06/01/game_design_analysis_world_of_goo" rel="alternate"/><published>2010-06-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Introduction&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;heading-ref&quot;&gt;Introduction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the second essay for the course Game Design and this thime I will be analysing the game &lt;a href=&quot;http://www.worldofgoo.com/&quot;&gt;World of Goo&lt;/a&gt; a bit.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/goo1.png&quot;&gt;
&lt;figcaption&gt;The first level
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The game is very simple. You begin with a structure and a few Goo balls, the charming balls bobbing around there, which you can drag and drop to build on the structure. Your goal is to reach the pipe and it will suck in the surviving Goo balls and you need to collect a certain amount of balls, in this case at least 4. All you ever use is your mouse and one button to pick up and place the balls.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/step-1.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/step-2.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/step-4.png&quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;A step by step of the core mechanics&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The beginning levels are very easy but it will get increasingly harder and you have to plan your building so you don’t use up too many Goo balls.&lt;/p&gt;
&lt;p&gt;But as it’s a physics game you will also have to think about gravity so your tower won’t topple over and crash, which will happen to you a lot in the later levels.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/bridge.png&quot;&gt;
&lt;figcaption&gt;Oh noes my bridge is collapsing!
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;That’s about the whole game concept right there; build structures to reach the pipe but use so few balls, or building blocks, as you can. You might think that it’s a shallow game with doing the same thing over and over – but you couldn’t be more wrong, there are a lot of different Goo balls to play around with; sticky balls, dangling balls, exploding balls, shooting balls, removable balls and more which will force you to change your build process in different directions. The level design is simply fantastic and it challenges your constructions and it makes the game very varied.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/balloons.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/sticky.png&quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;The levels are both fun and diverse&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The game which inspired World of Goo, namely Tower of Goo was an experimental one week, one person game with the aim of simply building a high tower and you can still do that in World of Goo in a sandbox mode and you can compete online on who makes the highest tower.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/levels.png&quot;&gt;
&lt;figcaption&gt;The level chooser screen, be proud of those flags!
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;If you like challenges there’s more to do: for every level there’s this extra hard ending criteria – a challenge – for you to get gray hairs from. There’s time challenges, constraints on number of moves and a minimum of balls collected and some of them are extremely though. If you’re successful you’ll get a nice little flag on the level chooser screen.&lt;/p&gt;
&lt;p&gt;The game is quite large with 5 different chapters and there’s around 10 levels each. Every chapter has it’s own theme and they vary quite a lot; there’s focus on explosions, balloons and there’s even Goo balls you can shoot! This gives the game fairly long but it manages to stay fresh all the way through.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/chapters.png&quot;&gt;
&lt;figcaption&gt;The 5 chapters + sandbox (Tower of Goo) is the World of Goo
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Analysis&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Analysis&quot; class=&quot;heading-ref&quot;&gt;Analysis&lt;/a&gt;&lt;/h2&gt;
&lt;section id=&quot;Actions-and-confirmation&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Actions-and-confirmation&quot; class=&quot;heading-ref&quot;&gt;Actions and confirmation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the things World of Goo does really well is to communicate to the player. When a first time player loads the first level it’s almost always clear what to do, you have this helpful sign showing your first move (drop a goo ball here) and you have this curious looking pipe just above you and not much else to distract you. After each level you get a score screen on how you did and both the level and world screen are helpfully showing your progress and what to do next. But to me the most impressive thing is how your actions are handled.&lt;/p&gt;
&lt;p&gt;When you hover your cursor over moving Goo balls or removable joints you’ll get a clear marker around the selected ball and it’ll stop and give you a cute look just to show you ‘Hey! It’s me you wanna pick up!’. Likewise when you have a ball selected and you’re moving it around for a good spot you’ll get a small notion of where it’s going to connect and always you have a nice big clear marker on where your cursor is.&lt;/p&gt;
&lt;figure class=&quot;flex-25&quot;&gt;
&lt;a href=&quot;/images/wog/select.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/select.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/wog/build.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/build.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/wog/shooting.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/shooting.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/wog/block.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/block.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Selecting, building, shooting and moving&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Visual confirmation in all honor but what really makes actions clear is the sounds. For every Goo ball hovered over and every joint constructed there’s a short confirmation of your action and for every dead Goo and every block crashed there’s an unique sound to let you know that something bad happened here in your little world. Every Goo that go down the pipe will emit a happy little laugh and you just love the hear that extra peculiar laugh which will tell you if you did complete the extra level challenge.&lt;/p&gt;
&lt;p&gt;I didn’t find any sound or visual effect for when your action fails, for example there were no error sound when trying to click in an empty space and the mouse pointer never acknowledged my clicks if they weren’t valid. But you can say that they aren’t necessary, because for every valid action and for every click you can make, where something actually happens, there’s always a confirmation sound and that is enough to let you know that something was successful and unsuccessful.&lt;/p&gt;
&lt;p&gt;Although simple the visual and auditive feedback works absolutely wonderful and I never had to wonder if my actions were registered, it felt like they always were and if things didn’t work as I wanted to I realized pretty quick that I was doing something wrong.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Varying-the-mechanics&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Varying-the-mechanics&quot; class=&quot;heading-ref&quot;&gt;Varying the mechanics&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The concept of the whole game is really quite simple, create structures with drag n’ drop Goo balls, add in some simple physics and you’re done. It’s amazing how captivating something simple as this can be and I believe it has a lot to do with the small incremental changes the game makes all the time.&lt;/p&gt;
&lt;p&gt;One thing the game does is introduce new Goo balls all the time; balls you can remove multiple times force you to climb and restructure, balloon Goos create interesting aerial acrobatics and a sticky Goo makes the structure mobile.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/liftoff.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/climb.png&quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;Lifting off and climbing is possible thanks to different Goo balls&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Even Goo’s with minor changes like industrial Goo which you can’t control or dangling Goo which will only dangle down gives a lot of depth to the game thanks to the great level design.&lt;/p&gt;
&lt;figure class=&quot;flex-25&quot;&gt;
&lt;a href=&quot;/images/wog/industry.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/industry.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/wog/water.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/water.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/wog/bone.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/bone.png&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/wog/cutter.png&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;/images/wog/cutter.png&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;There are lot’s and lot’s of levels which change the way you play&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It’s not just build straight up; it’s build around, use balloons to topple the tower from island to island and it’s surprising how hard it is to build a tower in water or in a tumbler, you really have to stop and think or else it won’t work. The game is constantly varying it’s mechanics and you have to change with it, you have to evolve to keep up.&lt;/p&gt;
&lt;p&gt;Perhaps the most radical experiment is the fourth chapter. We get new Goo’s that shoot! This is different from our regular balls that we can move around freely and they usually build or attach when we release them but these launch themselves when we drag n drop them. It’s the only way we can move them around and with one type we get to shoot and build.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/shoot-build.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/world-gravity.png&quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;Shooting Goo?&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Still staying true to the basic mechanics, select ball, drag n drop for effect with some physics and this could easily have been a game of it’s own.&lt;/p&gt;
&lt;p&gt;Going the other way around World of Goo also experiments with the drag n’ drop of Goo. They introduce block Goo which is immobile and it doesn’t walk around your structure like the other Goo and the only way you can move, the only way you can interact with them is to move them around and use them to block and for support or just to create a very unstable tower.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/blocking.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/tower-of-blocks.png&quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;Block Goo; immobile and blocky but yet they manage to add something to the game&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;All in all World of Goo uses their simple core concept to it’s limit with a ton of variation and experimentation and it makes the game feel novel all the way through those 50+ levels.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Consequences-of-the-rules&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Consequences-of-the-rules&quot; class=&quot;heading-ref&quot;&gt;Consequences of the rules&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;World of Goo is a physics based game; when building structures you need to compensate against gravity so your tower won’t collapse and you need to make sure your structure has enough joints so it can withstand tension and compression. Physics games are hard to create, you can’t rely on a perfect representation as it’s too hard to simulate perfectly and there are many edge cases you’ll have to handle.&lt;/p&gt;
&lt;p&gt;You can for example make it easier through this level if you force your structure into the wall and this “break” it. In real life a structure like this would completely break but in the game that doesn’t happen, the joints simply turn inwards and now you have a nice and short structure to move around.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/small.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/small2.png&quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;Small structures are easier to move around&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This happens because in the rules you can only break a structure if you either drop it into the ocean or on spikes, and loose them forever, or if you connect with a special construction destroying cogs. Here we exceed the tension and the compression and instead of breaking we get our joints twisted.&lt;/p&gt;
&lt;p&gt;You even have to abuse the rules because the extra hard level goals can’t be beat otherwise. I’m sure the creators chose to incorporate the bugs into the game and they even call them features in a way to create bigger challenges in the extra level requirements.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/throw.png &quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/hang2.png &quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/hang.png &quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;Some core game rules abuse&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;The left picture:&lt;/strong&gt;&lt;/strong&gt;
In World of Goo in some levels there are sleeping goo balls which you can’t get control of if you don’t get your construction close enough. But you can pick up and move around the balls and even throw them and if you do you can actually make the sleeping balls bounce around too. If you throw at the right angle you can bounce the sleeping balls close enough your structure and they’ll wake up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;The middle picture:&lt;/strong&gt;&lt;/strong&gt;
Your ultimate goal is the pipe and it will start sucking in your goo balls if you get your construction close. But if you have the green goo balls which you can remove from the structure you can get a small structure hanging from the pipe’s suction! Then you proceed to move the rest of the goo balls freely onto the structure and you will get a lot more balls collected. It’s so good you can actually get every goo ball, except one, if you do this trick. Incidentally the creators noticed this bug, or feature, when testing and so they set the extra level goal to precisely one less than your total balls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;The right picture:&lt;/strong&gt;&lt;/strong&gt;
In a level there’s a huge head which hangs from a small hook. When you’ve exploded the head you can get the hook to attach to the wall by throwing goo balls at your dangling structure. It will then connect to the wall because it doesn’t make any distinction to exploding heads or walls, it just sticks to it.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Mods&quot;&gt;
&lt;h3&gt;&lt;a href=&quot;#Mods&quot; class=&quot;heading-ref&quot;&gt;Mods&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The game is more or less a closed system but if you’re interested it isn’t too hard to create new levels, alter the online scoreboard (which has happened a lot) or even add new Goo balls. The site goofans.com is a dedicated site which collects fan-made levels and mods.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/color.png&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;/images/wog/jingleballs2.png&quot;&gt;
&lt;figcaption&gt;
&lt;p&gt;Colorful balloons and a new Christmas level&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There’s even a tool, &lt;a href=&quot;http://goofans.com/gootool/about&quot;&gt;GooTool&lt;/a&gt;, which is a tool which let’s you manage your installed mods, manage your profile stats, general options like screen resolution and even add in your own language.&lt;/p&gt;
&lt;p&gt;These changes, these mods, are mainly geared towards resources and not the actual game rules. It is possible to change them but then you more or less have to rewrite and mod the game on assembly level. This could be said about every computer game but it’s really hard and time consuming to do, but it sure is possible.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Conclusion&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Conclusion&quot; class=&quot;heading-ref&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think World of Goo is an excellent game and there are so many things it does right. The game is good about telling you what to do and when you’ve done something good by using both visuals and sound effects. The game basic foundation of the game is really quite simple but they manage to create a lot of diversity and this fresh feel throughout the whole game by introducing small, and big, variations to the core mechanics.&lt;/p&gt;
&lt;p&gt;The simple rules will create a few bugs and surprising side effects but they turn it around and they even call them features when they force you to use them if you want to complete the extra hard level requirements.&lt;/p&gt;
&lt;p&gt;There are a few mods and new levels out there if you hunger for more and with a little effort you can create your own, even if most of the game rules are quite inaccessible.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;References&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#References&quot; class=&quot;heading-ref&quot;&gt;References&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
Salen &amp;amp; Zimmerman, 2004. Rules of Play. The MIT Press.
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;http://2dboy.com/&quot;&gt;http://2dboy.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;http://www.worldofgoo.com/&quot;&gt;http://www.worldofgoo.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;http://goofans.com/&quot;&gt;http://goofans.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;http://goofans.com/gootool/about&quot;&gt;http://goofans.com/gootool/about&lt;/a&gt;  
Accessed may 1st
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
</content></entry><entry><title>Generating ideas</title><id>http://jonashietala.se/blog/2010/05/23/generating_ideas/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/05/23/generating_ideas" rel="alternate"/><published>2010-05-23T09:39:54+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I got a fairly fun assignment from the game design course I’m taking for once. I should come up with 50 ideas using my own idea generation technique.&lt;/p&gt;
&lt;p&gt;I used a sort of “notes in the basket” approach where you placed some notes with words in a basket and randomly drew two and then you should come up with something with the two words. But I’m too lazy to write a lot of notes and it’s pretty damn hard to come up with a lot of good words too, so I tried to automate the process.&lt;/p&gt;
&lt;p&gt;I searched for some random words and found this site: &lt;a href=&quot;http://www.wordswarm.net/&quot;&gt;http://www.wordswarm.net/&lt;/a&gt; and I pulled out a few pages and got a few thousand words. Then I made a very simple tool which randomly combines two lines from a file and creates a sentence, much like the you would with the notes but this is just so much faster. Granted I had a lot of shitty words and I got a lot of garbage lines but I could go through so many lines it was a very simple task to get these 50 one-lined game ideas.&lt;/p&gt;
&lt;p&gt;These are not fully fledged game ideas, but merely seeds from which you could grow a game.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pensionere wheelchair race&lt;/li&gt;
&lt;li&gt;Fish and surf on the fish&lt;/li&gt;
&lt;li&gt;Deep sun exploration&lt;/li&gt;
&lt;li&gt;VimCity - A simcity but with ascii chars which will teach you vim&lt;/li&gt;
&lt;li&gt;Crazy units RTS&lt;/li&gt;
&lt;li&gt;RTS with important landscapes - Destructable, things moving, rising water, paths in snow etc&lt;/li&gt;
&lt;li&gt;House destruction  - &lt;em&gt;explosions!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Hospital creation with strange diseases you need to cure&lt;/li&gt;
&lt;li&gt;Create Nautilus  - &lt;em&gt;an underwater city creator&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Prison diner maid  - &lt;em&gt;give lunch to hungry prisoners&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Prison break  - &lt;em&gt;with stealth, create stuff with different things&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Bread seller  - &lt;em&gt;bread maker tycoon?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Night debt collection hero&lt;/li&gt;
&lt;li&gt;Imprison Berth the jewel thief  - &lt;em&gt;police hunting a thief in the night/museum&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Feed azimutal, the mythic beast in the sky&lt;/li&gt;
&lt;li&gt;The 59th beetle-killer squads patriotic killings&lt;/li&gt;
&lt;li&gt;Trauma center boom&lt;/li&gt;
&lt;li&gt;Make mt. 63 a tourist franchise&lt;/li&gt;
&lt;li&gt;Chop the mighty “King’s wood” from the legendary forest of death&lt;/li&gt;
&lt;li&gt;Untagling Sarsenet  - &lt;em&gt;the predecessor to skynet&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The great pie theft&lt;/li&gt;
&lt;li&gt;Sawyer the egoist ant&lt;/li&gt;
&lt;li&gt;Herbsman Abdal, the lone man growing herbs in the desert&lt;/li&gt;
&lt;li&gt;Carving the first images  - &lt;em&gt;like caveman style&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Bart the Darting hero&lt;/li&gt;
&lt;li&gt;Brady the Big Eater glutton  - &lt;em&gt;Rush into restaurants and eat everything, then split&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The struggle against Montezuma II, A mayan RTS war game&lt;/li&gt;
&lt;li&gt;Industrializing Cakedoom&lt;/li&gt;
&lt;li&gt;Mini racers the beginning: Autobahn&lt;/li&gt;
&lt;li&gt;Saunter on thin ice  - &lt;em&gt;wannabe ice princess&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Clark the Corrupt and Ruler of the Rhen  - &lt;em&gt;screw your inhabitants and take all the money&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;A wooden submarine  - &lt;em&gt;the first submarine, the turtle&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Aristocrat apartment building&lt;/li&gt;
&lt;li&gt;Managing the missionaries hygiene&lt;/li&gt;
&lt;li&gt;The world’s best Toasts&lt;/li&gt;
&lt;li&gt;The raspberry in Cosmos&lt;/li&gt;
&lt;li&gt;The viking slap-up&lt;/li&gt;
&lt;li&gt;Digging after tea&lt;/li&gt;
&lt;li&gt;Colorizing the world with a trumpet&lt;/li&gt;
&lt;li&gt;Round Rod explores Square City&lt;/li&gt;
&lt;li&gt;Ordering the Oranges&lt;/li&gt;
&lt;li&gt;Smuggling over the boarder&lt;/li&gt;
&lt;li&gt;Life at the Toxic Waste Dump&lt;/li&gt;
&lt;li&gt;Creating a Ghost Town  - &lt;em&gt;with real ghosts who want to live their life&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Riding a Lawnmower and killing Gremlings&lt;/li&gt;
&lt;li&gt;Digging gold on Mars&lt;/li&gt;
&lt;li&gt;The life of a Bacteria, birth, mutation and world conquering&lt;/li&gt;
&lt;li&gt;Put the surfing Duck&lt;/li&gt;
&lt;li&gt;Butler who’s carrying silver&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>Competition Feedback</title><id>http://jonashietala.se/blog/2010/05/18/competition_feedback/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/05/18/competition_feedback" rel="alternate"/><published>2010-05-18T18:49:04+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The voting is over and I got a few ratings I want to comment on. You can view all ratings and comments &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-17/?action=preview&amp;amp;uid=1895&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They’re all from 1 to 5.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Innovation: 3.75&lt;/strong&gt;&lt;br /&gt;
This is by far the most positive of the bunch and the one button timing combination worked great!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fun: 3.29&lt;/strong&gt;&lt;br /&gt;
Again a good grade and I thought the game was fun although it became really frustrating.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Theme: 3.17&lt;/strong&gt;&lt;br /&gt;
The islands wasn’t very prominent in the game and the game could’ve been about anything really, but again I’m more than happy with the grade.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Graphics: 2.54&lt;/strong&gt;&lt;br /&gt;
Very simple and with some more effort it would’ve been better. But I’m happy, programmer graphics ftw!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audio: 2.14&lt;/strong&gt;&lt;br /&gt;
I only had two click sounds but still got fairly high. Many decided not to vote on it and I wouldn’t either. They were just last minutes add-ons but good to see someone liked it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Humor: 2.54&lt;/strong&gt;&lt;br /&gt;
I didn’t focus on this at all but got some decent grades from it anyway. Not sure if my graphics are &lt;em&gt;that&lt;/em&gt; ugly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overall: 3.13&lt;/strong&gt;&lt;br /&gt;
The most prestigious grade and it’s okay. I’m absolutely happy with it, especially since my desperate hope was to get &lt;em&gt;something&lt;/em&gt; playable out of this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Community: 1.64&lt;/strong&gt;&lt;br /&gt;
The community rating is for posts and stuff over at the Ludum Dare homepage. Sadly I didn’t spend time there, almost at all, so I can’t really say anything about this.&lt;/p&gt;
&lt;p&gt;Overall I’m really happy with everything and I’m really happy with my relatively good grades.&lt;/p&gt;
&lt;p&gt;I will do my very best to make my next game even better, but atm I can’t seem to decide which idea I want to work with (I have like 4-5 serious ideas I’d want to explore).&lt;/p&gt;
</content></entry><entry><title>Postmortem: Beebop The Island Hopper</title><id>http://jonashietala.se/blog/2010/04/26/postmortem__beebop_the_island_hopper/index.html</id><updated>2024-06-27T07:14:39+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/26/postmortem__beebop_the_island_hopper" rel="alternate"/><published>2010-04-26T18:56:59+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So I participated in the &lt;a href=&quot;http://ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt; for the first time and this is a postmortem of my game &lt;a href=&quot;/blog/2010/04/26/beebop_the_island_hopper/&quot;&gt;Beebop The Island Hopper&lt;/a&gt; for the theme &lt;em&gt;Islands&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;About Ludum Dare&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt; is a competition which runs maybe two times a year and the competition is 24 hours long with a specific theme. After the 48 hours are over everyone who submitted a game can rate the other games in different categories such as graphics, fun, theme and overall. &lt;a href=&quot;http://www.ludumdare.com/compo/about-ludum-dare/&quot;&gt;More info here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;The other entries&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-17/?action=preview&quot;&gt;View all 205 Ludum Dare 17 entries&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Holy hell &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-17/?action=rate&amp;amp;uid=491&quot;&gt;they&lt;/a&gt; &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-17/?action=rate&amp;amp;uid=1186&quot;&gt;look&lt;/a&gt; &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-17/?action=rate&amp;amp;uid=383&quot;&gt;absolutely&lt;/a&gt; &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-17/?action=rate&amp;amp;uid=1135&quot;&gt;fantastic&lt;/a&gt;! Taking part in a competition like this is so humbling, I can’t even begin to compare myself to the best games out there. But that’s good, I have games and creators to look up to and so I know how I can improve. Which by the way I can do with everything.&lt;/p&gt;
&lt;h1&gt;Stats&lt;/h1&gt;
&lt;p&gt;This time I didn’t log my hours and so I don’t have a good enough graph to show you. Thinking back I worked about 8 hours during this 48 hour challenge, two of them on Saturday and the remaining six late on Sunday. I didn’t work many hours on this game but the hours I did work were really productive.&lt;/p&gt;
&lt;h1&gt;Pressure&lt;/h1&gt;
&lt;p&gt;Once again I think I’ve proven that pressure is the best motivator. The game feels as finished as any other game I’ve made. Sure it’s not the biggest game and it has very limited features but it was made in less than a third of the time. Actually even less if you count the hours and not the days!&lt;/p&gt;
&lt;h1&gt;The Game&lt;/h1&gt;
&lt;p&gt;Even despite it being extremely simple it did suck up a bit of my time when I tried to beat it (which will take you a minute or two). I kinda liked playing it.&lt;/p&gt;
&lt;p&gt;The graphics are pretty good, I have a pretty special style and I personally think it’s not half-bad and hopefully you like it too. The music and sound are… well there is no music and I have like three sound effects in total - two of them are different kinds of clicks!&lt;/p&gt;
&lt;p&gt;Overall I like it, but it’s nothing really special. If I would try to give it an unbiased score (we all think our children are fantastic after all) it would probably be a &lt;em&gt;3 of 5&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;The pressure of a deadline is a powerful motivator and now I’ve found that no more than a week, or even a weekend, is enough to make a game. And it might even end up being enjoyable.&lt;/p&gt;
</content></entry><entry><title>Beebop The Island Hopper</title><id>http://jonashietala.se/blog/2010/04/26/beebop_the_island_hopper/index.html</id><updated>2026-04-27T11:09:32+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/26/beebop_the_island_hopper" rel="alternate"/><published>2010-04-26T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s here! The stuff of dreams, an entry for the epic &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare 17&lt;/a&gt; has been made! For those who don’t know it’s a 48 hour game making competition which actually is pretty silly. Even more silly is my two hours of commitment yesterday but late this night at about 03:05 I am now, finally, writing this post! The theme was &lt;em&gt;islands&lt;/em&gt; and this is what I came up with:&lt;/p&gt;
&lt;h1&gt;Beebop The Island Hopper&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/beepo1.png&quot; alt=&quot;&quot; /&gt;  &lt;img src=&quot;/images/games/thumbs/beepo2.png&quot; alt=&quot;&quot; /&gt;  &lt;img src=&quot;/images/games/thumbs/beepo3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Controls&lt;/h1&gt;
&lt;p&gt;Any Key.&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Sound effects:&lt;/em&gt; Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Random Coolness:&lt;/em&gt; &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Rest:&lt;/em&gt; Me&lt;/p&gt;
&lt;h1&gt;Source&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/ludumdare17&quot;&gt;https://codeberg.org/treeman/ludumdare17&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>Ludum Dare 17 - an hour or two into it</title><id>http://jonashietala.se/blog/2010/04/24/ludum_dare_17_-_an_hour_or_two_into_it/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/24/ludum_dare_17_-_an_hour_or_two_into_it" rel="alternate"/><published>2010-04-24T22:56:54+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I decided to participate in the &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt; this time, even though I’ve spent the whole day on a massage course (which by the way was pretty darn good), and about halfway there this is what I’ve done:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/ld17.png&quot; /&gt;
&lt;figcaption&gt;Chockingly… ugly&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;All is not what meets the eye though, I’ve got the basics done with fully scriptable islands and actually the very basic gameplay too. Now it’s just the blows and whistles left (meaning it’s about 90% left).&lt;/p&gt;
</content></entry><entry><title>Evolution of RTS games</title><id>http://jonashietala.se/blog/2010/04/23/evolution_of_rts_games/index.html</id><updated>2024-09-11T08:18:12+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/23/evolution_of_rts_games" rel="alternate"/><published>2010-04-23T10:00:40+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;/p&gt;
&lt;section id=&quot;Introduction&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Introduction&quot; class=&quot;heading-ref&quot;&gt;Introduction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is an essay for the course Game Design and I’m going to give you a ride through the evolution of RTS game genre. I like RTS games and I’ve played them for as long as I can remember, from the classic Red Alert and Age of Empires to the newer Supreme Commander and Starcraft 2 (beta).&lt;/p&gt;
&lt;p&gt;First of all what is a Real Time Strategy game? How do we narrow it down? The first distinction I’d like to draw is the Real Time part. Games like chess and civilization are most certainly strategy games but they are not executed in real time. Instead you wait for your turn and then make your move. Turn-based games like these are in my mind not RTS games. Neither are “God games” like SimCity and The Sims. You have very few boundaries and you can do what you want, when you want and how you want. But I think of RTS games more as a competition – a race against time.&lt;/p&gt;
&lt;p&gt;I’d like to draw a loose definition for an RTS: “harvest, build and destroy”. Practically all RTS games are based around the idea to get money or some kind of resources to build up an army and proceed to destroy your enemy.&lt;/p&gt;
&lt;p&gt;I will focus more on the beginning RTS games as they are still the main influence to all RTS games and then I will a bit more quickly go through the modern games and the modern ideas that continues to drive RTS forward.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-Journey-Begins&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-Journey-Begins&quot; class=&quot;heading-ref&quot;&gt;The Journey Begins&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the beginning there was no RTS games. Hard to imagine I know but that’s the truth. When the idea of RTS was born the gaming scene looked a lot different from now. In the 1980’s Nintendo had blown new life into the video game industry and it was the simple games that held us entertained, games like Pong, Tetris and Pac-Man. However the tides were shifting and more advanced games like SimCity were on the rise.&lt;/p&gt;
&lt;p&gt;Dune II (1992) wasn’t the first RTS game, there had been several games with RTS influence in them but this was the first complete RTS. The game was all about control. You chose exactly what units to build and when to build them and you could command every single unit at will – perhaps drive it across the map to check what your opponent is building?&lt;/p&gt;
&lt;p&gt;The game introduced the concept of a tech-tree (Technology Tree) where you could “tech up” to stronger but more expensive tanks or you could continue to build cheap tanks. Gone where the days when you had to rely on a rock-paper-scissor balance between units, such as tank beats artillery which beats infantry which beats tanks, and instead you had the choice of countering a tank with a bigger tank! Or with a mind-control tank or you could choose to destroy the factory producing the tanks. Choosing the right time to climb up the tech-tree became vital to your success but it was complicated by “the shroud” which was a black fog covering the map where you haven’t been. This in turn forced players to scout and check what the opponent is doing having to constantly revise what units he should build and if he had to tech up.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rts/dune-2.png&quot;&gt;
&lt;figcaption&gt;The sandy land of Dune 2
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Perhaps the most revolutionary concept Dune introduced was the resource system. To build things you had to have spice, the game’s only resource, and to get spice you had to harvest it on the map and bring it home to convert it to money and then units or buildings. What this practically means is the player had to have control of the map, he had to have a place he could get spice or else he would probably die. The concept of map-control is something that is driving virtually all RTS games to date.
The first online capable game was Warcraft: Orcs and Humans (1994) but the online boom wouldn’t come just yet. Instead it was the game Command &amp;amp; Conquer (1995) who refined RTS a bit more. It wasn’t a graphical masterpiece nor very complex instead it’s simple but it just works. The game screams atmosphere and war. All the units were pretty straightforward (I mean who doesn’t know an apache, a rocket launcher or an M1A1 tank?) so it was pretty easy to pick up. But beneath the simple exterior lay a surprisingly deep game.&lt;/p&gt;
&lt;p&gt;The game built on Dune 2 and in fact some fans nicknamed it Dune 3; the shroud and the resource system was the same and the tech-tree was built upon and it introduced the concept of a BO (Build Order – a predefined order to build things to maximize unit production or similar). C&amp;amp;C furthered the sense of control, in Dune you could just select one unit at a time but here you could select several, you could then store it in a group 0-9 and whenever you pressed the number again the group associated with it would be selected.&lt;/p&gt;
&lt;p&gt;Instead of the “tank, bigger tank, biggest tank” from Dune C&amp;amp;C furthered the unit differences with tanks and infantry. Infantry was weak and could even be run over by the tanks with a satisfying splat sound, but they were dirt cheap and vital for early scouting. Tanks on the other hand were strong and fast but they were expensive and they had to rely on driving over infantry in order to effectively kill them. This gave the game a whole new level depth.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-RTS-Boom&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-RTS-Boom&quot; class=&quot;heading-ref&quot;&gt;The RTS Boom&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Warcraft II: Tides of Darkness (1995) became the first mega-successful RTS game. For some the interface was a letdown with no groups or build queues but instead it introduced the standard right click. Example with a peon: if you right click on a gold mine he will harvest and if you click on an enemy he will attack. It also allowed you to build anywhere opening for the oh so popular tower rush (build offensive defense towers). For the first time we got to have full naval battles with battleships, submarines and even a very own naval-resource. They improved the shroud and turned it into the now standard Fog of War where the fog regrows if you don’t have any units there.&lt;/p&gt;
&lt;p&gt;But the thing that really set Warcraft II apart was the online multiplayer. A huge community gathered and spawned leagues, clans and ladders and essentially creating the base of modern competitive RTS gaming.&lt;/p&gt;
&lt;p&gt;Command &amp;amp; Conquer Red Alert (1996) was the original C&amp;amp;C but more and better. It kept the defining pieces but moved up the pace with high yield minerals and a stronger focus on tank warfare. In fact the focus on tanks was so strong that it introduced the concept of a “tank rush” where you amass a lots of tanks quickly and then rush your opponent to catch him of guard. The factions were different and unique and featured for the first time full featured land, sea and air combat. Red Alert also has a crazy and good story where Einstein witnesses the horrors of Hitler and proceeds to g back in time and kill, but without the competition for Stalin a new war breaks out. This placed new importance on the story in RTS games, a tradition which still continues today.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rts/redalert.png&quot;&gt;
&lt;figcaption&gt;We can spot Red Alert’s mighty mammoth tank
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;If you think about classical RTS games the chances are high you’ll think about Age of Empires (1997). The game is one of the most influential RTS games and if you’ve ever played it it’s easy to see why. It’s balanced, polished and very deep. It’s one of the first games to introduce the concept of “Ages”, essentially tiers in a tech tree. There are four ages which let’s you progress from the very basic clubmen to advanced bowmen and even war elephants. The whole system is nicely done and the progression to higher tiers is fluent and it adds a lot of depth to the game. The resource system is still one of the most complex in any RTS with a whopping four resources for you to balance. Another new concept was the random maps. This way every game was a whole new experience with lots of different chokes and the importance of scouting was set on a whole new level.&lt;/p&gt;
&lt;p&gt;There are games that would introduce one or two novel ideas and then there is Total Annihilation (1997). The game was the first 3D RTS game and it featured real physics simulation. Gone where the days when your units would hit instantaneously and without fail, here everything was simulated; on bumpy terrain the shots could fire into the ground, the front units would absorb and block hits and higher terrain would give the benefit of an increased range. TA was one of the first games where units could shoot while moving, making for some interesting run and dodge tactics. Dead units would even leave wreckages on the  battlefield, wreckage that would block movement and you could reclaim them and regain some of the metal you used to build them.&lt;/p&gt;
&lt;p&gt;When we’re on the topic of metal and resources – TA has one of the most unique resource systems to date: they’re unlimited. Unlike games like C&amp;amp;C with a finite resource system you never had to worry if you had enough, metal and energy would be regenerated infinitely so it was never a question if you could afford it, but how long it would take to be built. TA reintroduced the “Hero unit” from the era before Dune II, where you actually were a unit and if that died you loose.&lt;/p&gt;
&lt;p&gt;TA was more a game without limits than anything before – battles with hundreds of units were commonplace and when the big units in other games fired across the screen, the big guns in TA fired across tens of screens or even across the whole map! Where other games had strong Rock-Paper-Scissor counters TA had none. You could even fire artillery at airplanes (although pretty useless). Instead the balance revolved around unit speeds, turning times and overkill.&lt;/p&gt;
&lt;p&gt;Until this day, almost 12 years later, Starcraft (1998) is still the most competitively played RTS. The game had a great story and had three completely different races. Other games differentiated their factions with units but in Starcraft even the way you built things was different. But the thing that sets it apart from anything else is the community and in particular the competitive gaming scene that gathered around it. It’s so ridiculously popular in South Korea that it’s considered the National Sport there and the players are treated as rock-stars.&lt;/p&gt;
&lt;p&gt;Why did this game become so popular? I don’t know; it took almost a decade to get it balanced good and it isn’t extremely fast paced. It’s really fun to play but almost more importantly is that it’s fun to watch, the immersion factor and the excitement of a high skilled game is unparalleled and I think that’s what sparked the formation of a dedicated community. Then the community in itself is a reason why Starcraft has stood the test of time – the formation of pro leagues, great map support and excellent coverage has made sure the community has flourished.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rts/sc.png&quot;&gt;
&lt;figcaption&gt;Starcraft, the most successful RTS game yet
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Life-After-the-Boom&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Life-After-the-Boom&quot; class=&quot;heading-ref&quot;&gt;Life After the Boom&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The success of RTS as a genre sparked the creation of a lot of pretty similar, but often very good, games like one of my personal memories KKnD (1997). However it didn’t take long until the next big revolution: true 3D brought to you by Homeworld (1999). Total Annihilation had used 3D terrain but Homeworld set the player in space and gave the freedom of the Z-dimension. Instead of just moving on a flat, albeit bumpy, surface you could now move freely in any direction you’d like. In addition Homeworld became known for it’s atmospheric and rich story and they introduced persistence in the single player campaign. It means that you would retain all of your units and upgrades from your last mission and if you had finished it badly with only a few units the next mission would prove impossible and you had to replay it.&lt;/p&gt;
&lt;p&gt;Building on a concept and improving it has been heavily used in RTS and it has brought us some of the very good games. Age of Empires II (1999) was all of the original but better. Command &amp;amp; Conquer: Red Alert 2 (2000) upped the pace of of older C&amp;amp;C games and created a fun, with some good humor, easy to pick up but hard to master classic RTS game. Red Alert 2 still had a cartoony 2D look who many loved but it was to become one of the last 2D RTS games.&lt;/p&gt;
&lt;p&gt;Age of Mythology (2002) was a spin-off from the Age of Empires with all its goodness but with additional “God powers”. Rise of Nations (2003) incorporated classical board game features such as territory and it tried out a resource system with a whopping 6 resources (crazy!).&lt;/p&gt;
&lt;p&gt;Warcraft III (2002) continued on where Warcraft II left but with added focus on abilities and RPG like hero units. The game is very centered around you gaining experience and leveling up your hero by killing neutral monsters, called creeping, as the three heroes you could have are more powerful than the rest of your army. Instead of a hard unit cap like in Starcraft Warcraft tried the approach with upkeep: if you have a large population you’ll gain less gold and it worked pretty well as multiple expansions would do more harm than good.&lt;/p&gt;
&lt;p&gt;The focus on heroes and abilities made the game really micro intense (taking care of individual units) as opposed to the very macro (economy) centered Starcraft. (It’s pretty amusing in the current Starcraft 2 beta where you can actually see what game the top players used to play, Starcraft players usually have great macro but pretty bad micro whereas top Warcraft 3 players micro a few units but their economy is bad.)&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rts/Warcraft-3.png&quot;&gt;
&lt;figcaption&gt;A human player harassing an Orc in Warcraft 3
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Command &amp;amp; Conquer Generals (2003) shifted the focus for the C&amp;amp;C series. It made the building panel a bit more free, so you could easier build where and what you wanted, it had radically different factions and sub-factions but it had a very poor story but perhaps the most noteworthy addition was that upgrade change unit behavior instead of simply making them deal +1 damage. For example infantry was weak against tanks but with an armor-piercing upgrade they could destroy it.&lt;/p&gt;
&lt;p&gt;Lord of the Rings: The Battle for Middle Earth (2004) had a pretty interesting and different build system. Where other games placed no limits on where you could build the game only allowed you to build on specific places and they were very limited. This forced you to really think about what to build – one mismatched building and you could get your entire army mismatched against your enemy. It also had a sort of RPG experience points tree whit a lot of different power ups you could have, but these too were limited and forced the player to make hard decisions, and hard decisions are good.&lt;/p&gt;
&lt;p&gt;Dawn of War: Warhammer 40,000 (2004) changed the well known resource system, instead of harvesting the player was given “map points” combined with an in-house generated resource. You also had squads, which were treated as one unit for easier control and as several when in battle.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-Modern-Age&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#The-Modern-Age&quot; class=&quot;heading-ref&quot;&gt;The Modern Age&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Company of Heroes (2006) is a pretty special game. It fuses the cinematic experience from an FPS with the tactical and strategical depth from an RTS. You command a lot less units and you’re a lot closer to the battlefield. The environment is almost fully destructible and your units will take shelter behind anything they can find. Things like where you attack a tank became important as the armor was considerably weaker in the back and ammunition and fuel was considered a scarce resource.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rts/coh.png&quot;&gt;
&lt;figcaption&gt;The immersion of Company of Heroes is simply stunning
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;World in Conflict (2009) took the tactics even further and is considered an RTT – Real Time Tactics. In WiC there are no resources, just a sum given in the start of the game for you to call in units with. When the units are killed the points are slowly given back ensuring you won’t run out of units. The game is solely focused on controlling your units and thus isn’t really a true RTS in my eyes but a game bordering between the two.&lt;/p&gt;
&lt;p&gt;Supreme Commander (2007) is the spiritual successor to Total Annihilation and it stands in stark contrast to WiC’s tactical focus – here it’s about the broad strokes man. Given the strategic zoom you can zoom out until you can see the whole battlefield and all the hundreds of units are there for you to command. The scale is huge, nukes and experimental super units trashing around gives the game an epic feel. But there’s a lot more to Supcom than watching huge battles, it’s using the whole TA system with infinite economy, wreckages and no hard counters. We have new intelligence modes; in addition to line of sight as in almost every other games there are radar, sonar and omni (see all). To counter these we get cloaking and radar jamming units. Another thing Supcom does well is the improved interface with infinite queues which tie well with the infinite resources so you don’t have to babysit your factories to get them to continually produce units.&lt;/p&gt;
&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;/images/rts/fa.png&quot;&gt;
&lt;figcaption&gt;Me and Toejams showing off in Supreme Commander
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Today there are both big scaled games like Hearts of Iron III (2008) and small-scale like Company of Heroes. There are games that relies on the old tried-but-true formula (Starcraft 2 currently in beta) and other more novel (Darwinia 2005). If you look closely you’ll notice the core the old RTS games are still here, unchanged. Starcraft 2’s resource system is basically the same as in Dune II and grouping are still the same as in the original C&amp;amp;C. Games are still living on, and building on, the successful ideas of the past (the new C&amp;amp;C, AoE3 etc) and I personally think they will continue to entertain us, Dune II style, for at least a couple of decades more.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Conclusion&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#Conclusion&quot; class=&quot;heading-ref&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ve been through the evolution of the RTS from the beginning with Dune II until modern games like Supreme Commander and World in Conflict. The simple one resource system has given birth to four and even six resource systems and some games have opted for “map points” or different infinite resources. The simple shroud concept has turned into the now standard Fog of War and there has been some advanced intelligence gathering going on in a few games. The Hero concept with borrowed RPG elements are now standard in many games and the tech tree has been branched into several different flavors. The scale has both been amplified and minimized and units has differentiated themselves from each other.&lt;/p&gt;
&lt;p&gt;Thanks to the online multiplayer pioneered almost 15 years ago has turned a little niche genre into a mega-industry with competitions held in several different games and countries. But where the genre is heading is anyones guess, but whichever way it’s heading I’m sure it will continue to entertain and surprise you.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;References&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;#References&quot; class=&quot;heading-ref&quot;&gt;References&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everything accessed 21 mars 2010&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.gamespot.com/gamespot/features/all/real_time/&quot;&gt;gamespot1&lt;/a&gt;, &lt;a href=&quot;http://www.gamespot.com/gamespot/features/all/realtime_pt2/index.html&quot;&gt;gamespot2&lt;/a&gt;&lt;br&gt;
History of RTS during the years 1989-2001. Pretty good.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.gamereplays.org/portals.php?show=page&amp;amp;name=the_history_of_real_time_strategy_pt1&amp;amp;st=3&quot;&gt;Gamereplays RTS history&lt;/a&gt;, a great resource written by several RTS enthusiasts.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://gamingbolt.com/2009/09/20/top-20-real-time-strategy-games-of-all-time/&quot;&gt;A top 20 list&lt;/a&gt;, take it with a grain of salt. Used for inspiration.&lt;/p&gt;
&lt;p&gt;From wikipedia various stuff (mainly dates):&lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Dune_%28novel%29&quot;&gt;Dune the novel&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Warcraft:_Orcs_%26_Humans&quot;&gt;Warcraft: Orcs and Humans&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Darwinia_%28video_game%29&quot;&gt;Darwinia&lt;/a&gt;  &lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Age_of_Empires_II:_The_Age_of_Kings&quot;&gt;Age of Empires II: The Age of Kings&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/KKnD&quot;&gt;KKnD&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Age_of_mythology&quot;&gt;Age of Mythology&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/World_in_Conflict&quot;&gt;World in Conflict&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Hearts_of_iron_3&quot;&gt;Hearts of Iron 3&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
</content></entry><entry><title>Before the Games: The Site</title><id>http://jonashietala.se/blog/2010/04/16/before_the_games_the_site/index.html</id><updated>2026-04-27T11:10:00+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/16/before_the_games_the_site" rel="alternate"/><published>2010-04-16T12:39:55+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’ve got some things I want to do before I start with my next game and they’re all about improving the site. The last week or so has been extremely productive with me throwing out a lot of wasted code, speeding up the site and adding/removing features and I want to continue with that and get the things done now when I’m in the flow.&lt;/p&gt;
&lt;p&gt;You can find the whole source for the site, excluding a few security related files ofc, &lt;a href=&quot;https://codeberg.org/treeman/&quot;&gt;on github&lt;/a&gt; where I’ve also uploaded a small to-do list and some ideas I might want to implement.&lt;/p&gt;
&lt;p&gt;Here’s a small summary of the stuff:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Allow editing all the information pages without doing it through phpmyadmin, merge it together with the post editing.&lt;/li&gt;
&lt;li&gt;Change the layout of adding comments and it’s preview, try unhide it.&lt;/li&gt;
&lt;li&gt;Fix the layout of search and possibly tweak the inner workings&lt;/li&gt;
&lt;li&gt;Revamp archive page, maybe use it as a sitemap?&lt;/li&gt;
&lt;li&gt;Add read next/previous posts on post and older/newer posts?&lt;/li&gt;
&lt;li&gt;Make comment editing work, for guests too.&lt;/li&gt;
&lt;li&gt;Statistics!! I have third party statistics but I want stats for the most active commenter and other stuff.&lt;/li&gt;
&lt;li&gt;A greater 404 page&lt;/li&gt;
&lt;li&gt;Refactor, remove garbage code and refactor some more.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’m itching a little bit about a new game, but first thing’s first.&lt;/p&gt;
</content></entry><entry><title>Widening the horizon</title><id>http://jonashietala.se/blog/2010/04/10/widening_the_horizon/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/10/widening_the_horizon" rel="alternate"/><published>2010-04-10T16:15:16+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This is a game making site but where are the games? What gives?&lt;/p&gt;
&lt;p&gt;I’ve been slightly less motivated in making games lately and I’ve been doing different things, just to get my ideas and my motivation up. As I said in an &lt;a href=&quot;/blog/2010/03/30/the_experimental_games&quot;&gt;earlier post&lt;/a&gt; I wanted a break from Experimental Games and I want to spend more time on each game just to get the quality of the games up.&lt;/p&gt;
&lt;p&gt;Lately I’ve been using &lt;a href=&quot;http://www.vim.org/&quot;&gt;vim&lt;/a&gt; and I really like it but the learning curve is really high, so why not make a game about it? To make the learning progress easier and hopefully even somewhat fun. I haven’t come up with a great idea yet, and thus I haven’t started, but I’m pretty optimistic.&lt;/p&gt;
&lt;p&gt;I also &lt;a href=&quot;/blog/2010/03/25/no_game_this_month&quot;&gt;mentioned&lt;/a&gt; &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt; but as the looks of things it ain’t gonna happen this time. I’ve got a massage course the whole weekend timed on just as the 48 hour game making competition is and I don’t think I wanna stress myself to manage the both of them.&lt;/p&gt;
&lt;p&gt;Instead for a game I’ve been focusing on learning &lt;a href=&quot;http://haskell.org/&quot;&gt;Haskell&lt;/a&gt; and on improving this site. Trying out different stuff like trying a new paradigm and trying out different languages is a really good way of &lt;a href=&quot;http://www.codinghorror.com/blog/2009/03/sharpening-the-saw.html&quot;&gt;Sharpening your Saw&lt;/a&gt;. Yes technically he meant doing things not related to programming, such as math, but I still see it as doing something completely different and improving while doing that.&lt;/p&gt;
&lt;p&gt;For example &lt;a href=&quot;http://kohanaframework.org/&quot;&gt;Kohana&lt;/a&gt;, the framework this site is built on, has made me think more about tools and frameworks instead of just language features as it transformed my awful, hackish site into this beautiful little thing literally in the blink of an eye. Or take &lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt; which took my epic cross-browser checks and transformed it into beautiful code. These two seemingly small changes made the boring web developer process &lt;em&gt;really fun&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Yeah that’s what I’ve been doing; I’ve been widening my horizon and I’ve been having fun at the process! &lt;em&gt;Wooo&lt;/em&gt;&lt;/p&gt;
</content></entry><entry><title>The games that make me who I am</title><id>http://jonashietala.se/blog/2010/04/06/the_games_that_make_me_who_i_am/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/06/the_games_that_make_me_who_i_am" rel="alternate"/><published>2010-04-06T11:51:36+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I read &lt;a href=&quot;http://pathdependent.com/2010/04/04/on-fiction/&quot;&gt;an article&lt;/a&gt; the other day where he met someone who didn’t read fiction:&lt;/p&gt;
&lt;blockquote&gt;He suggested that fiction was a waste of his time — he read to learn, not for &quot;mere&quot; entertainment&lt;/blockquote&gt;
&lt;p&gt;I don’t agree with this view and neither did he:&lt;/p&gt;
&lt;blockquote&gt;Fiction allows you to be part of situations that are unlikely to happen otherwise. You can experience thousands of years worth of events by reading fiction. Yes, it is true that what happens to you in real-life — with it’s finality and incomparably richer stimulation – out-weighs that of a book. However, the course altering moments in life are infrequent. Fiction provides a means of accelerating your “personal growth.”&lt;/blockquote&gt;
&lt;p&gt;He then gives us a list of fiction characters who has made him who he is, many small pieces of trait that has become a part of him.&lt;/p&gt;
&lt;p&gt;Interesting I thought and I began thinking of what characters I could identify with (&lt;a href=&quot;http://en.wikipedia.org/wiki/Lincoln_Rhyme&quot;&gt;Lincoln Rhyme&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Robert_Langdon&quot;&gt;Robert Langdon&lt;/a&gt; comes to mind) but then I started thinking of &lt;em&gt;games&lt;/em&gt;. What games has made me who I am? It’s not an easy answer and it’ll never become exhaustive but it’s interesting to think about and here’s my try:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worms&lt;/strong&gt;&lt;br /&gt;
I played the demo of Worms 2 to death, I ran to my friend all the time to play Worms Armageddon and I’ve been addicted to blasting ugly worms with banana bombs ever since.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RollerCoaster Tycoon&lt;/strong&gt;&lt;br /&gt;
I love rollercoasters and I love to build stuff so naturally I played the games a ton… I’m still tingling with excitement when I think of building a super-coaster. The builder that is me was born with this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hospital Tycoon&lt;/strong&gt;&lt;br /&gt;
Another constructor game with hilarious humor and I’m still harboring thoughts of resurrecting this beauty as a new game. I think it was one of the first games to make me think about actually making games instead of just playing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Counter-Strike Source&lt;/strong&gt;&lt;br /&gt;
The best anger management there is. Or well I’m not really civil when playing it but it lets me went out pretty damn good, but don’t sit near me when I’m playing - it’s not good for your ears.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;World of Goo&lt;/strong&gt;&lt;br /&gt;
The game that opened my eyes to the wonders of Indie Games.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supreme Commander&lt;/strong&gt;&lt;br /&gt;
Introduced me to the world of competitive gaming, or rather the competitive mindset. It also helped me become a better person by helping and being a part of a great community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Evil Genius&lt;/strong&gt;&lt;br /&gt;
Humor + Base Building = Epic Win.&lt;/p&gt;
&lt;p&gt;These are just a few games from the top of my head, some had big impacts and some slightly less so.&lt;/p&gt;
&lt;p&gt;We started with a quote and that’s how we’ll end it:&lt;/p&gt;
&lt;blockquote&gt;I am the product of my parents, my friends, my life, my experiences…and my teachers.&lt;/blockquote&gt;
</content></entry><entry><title>Death to the Forum</title><id>http://jonashietala.se/blog/2010/04/02/death_to_the_forum/index.html</id><updated>2024-07-09T12:12:24+00:00</updated><link href="https://www.jonashietala.se/blog/2010/04/02/death_to_the_forum" rel="alternate"/><published>2010-04-02T17:54:52+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Well it was fun while it lasted, but now it’s gone and it’ll stay gone for a long time I think. It was mainly a test to see if I could do it and I’m really proud of my styling of it but it’s deader than in a grave, which isn’t really surprising, and it bothered me that I didn’t write it myself - like really bothered me.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.phpbb.com/&quot;&gt;phpBB&lt;/a&gt; is fantastic in many ways; easy, fast and easily managed but it just didn’t feel right as I hadn’t done it. Kinda the same as why I’m not using any popular blog tool but I’ve rolled my own. It feels pretty good to use a site you’ve written completely yourself…&lt;/p&gt;
&lt;p&gt;And no I don’t want to write my own forum now, for now I’ll stick with a tweak here a tweak there on the site.&lt;/p&gt;
</content></entry><entry><title>The Experimental Games</title><id>http://jonashietala.se/blog/2010/03/30/the_experimental_games/index.html</id><updated>2024-06-27T07:47:15+00:00</updated><link href="https://www.jonashietala.se/blog/2010/03/30/the_experimental_games" rel="alternate"/><published>2010-03-30T11:26:56+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s been nine months since I started doing Experimental Games and I think it’s time to evaluate and maybe go in a new direction.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2009/07/21/the_first_worst_post&quot;&gt;At first&lt;/a&gt; I had been stuck for ages with my never-ending projects and I had literally nothing to show for all my coding. Well now things have changed a bit: I’ve successfully released &lt;em&gt;seven experimental games&lt;/em&gt;, games that more or less are playable, working and sometimes even fun! These months have taught me that games aren’t impossible year long projects, they don’t have to be perfect to be enjoyable and above all they taught me to get things done!&lt;/p&gt;
&lt;p&gt;Here are a few lessons I learned the hard way.&lt;/p&gt;
&lt;h1&gt;Iterate&lt;/h1&gt;
&lt;p&gt;Don’t try to make the game perfect from the start cause it won’t be perfect and it won’t be pretty. Instead create the ugliest, crappiest playable version of your game you can and then work from there. The best games where those who got playable the earliest: &lt;a href=&quot;/blog/2009/10/13/menucity/&quot;&gt;MenuCity&lt;/a&gt;, &lt;a href=&quot;/blog/2009/09/20/bugger/&quot;&gt;Bugger&lt;/a&gt; and &lt;a href=&quot;/blog/2009/11/25/jonas_icecream_stand/&quot;&gt;Jonas IceCream Stand&lt;/a&gt;. The other crappier games such as &lt;a href=&quot;/blog/2010/02/28/a_geek_valentine/&quot;&gt;A Geek Valentine&lt;/a&gt; and &lt;a href=&quot;/blog/2009/08/20/black_and_white/&quot;&gt;Black and White&lt;/a&gt; got playable just in a very late stage and indeed they also became the least fun.&lt;/p&gt;
&lt;p&gt;Fun isn’t created on the spot - it’s created through iterations. It’s like carving a wood figure. You don’t create it with a big slash, you carefully chop the wood off little by little until the figure is complete. This is how I think good, fun games are made.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/balls-leap.png&quot; /&gt;
&lt;figcaption&gt;This quantum leap wasn’t achieved with a big chop, but with many smaller ones&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Get things done&lt;/h1&gt;
&lt;p&gt;This is the thing that changed with me the most. At first I thought games where all about the planning stage - the idea stage. It’s important to have a great idea and it’s good to write down things sure but you can’t just sit on your ass doing the big talk and not actually do anything. As said about iteration you can’t make the game perfect from the start and you can’t the whole game from the start either. The game will change and your idea about what’s good for the game will change too.&lt;/p&gt;
&lt;p&gt;Take for example my latest game &lt;a href=&quot;/blog/2010/02/28/a_geek_valentine/&quot;&gt;A Geek Valentine&lt;/a&gt;. I had envisioned the game as a game where you built trap combos from a top down point of view. But the game changed into a pac-man type (I’m not all too happy about it though). For better or worse games and ideas change, stop planning and start getting shit done.&lt;/p&gt;
&lt;h1&gt;Set Goals&lt;/h1&gt;
&lt;p&gt;In December I had the truly great theme &lt;a href=&quot;/blog/2009/12/04/december_theme_new_world_order&quot;&gt;New World Order&lt;/a&gt; and it spawned the best game idea I’ve had, a sort of SimCity game but instead of building stuff you plot to take over the city and taint it with your evil propaganda. Like in North Korea or in the old Soviet. But the game was not to be.&lt;/p&gt;
&lt;p&gt;Why you ask? I think it’s because I never had a goal - &lt;a href=&quot;/blog/2009/12/14/breaking_the_rule_of_three&quot;&gt;I broke the one week rule&lt;/a&gt; and I could just push the deadline further and further and I never got anything done. With other games when I was at the 2-3 last days I always got a big energy boost and I always managed to get the game finished. But here I could just say “meh, I’ll do it later” and so it never got done. It’s &lt;a href=&quot;http://www.wired.com/magazine/2009/12/fail_duke_nukem/all/1&quot;&gt;Duke Nukem Forever&lt;/a&gt; all over again (maybe a bit smaller okay). Goals will help immensely to get things done.&lt;/p&gt;
&lt;h1&gt;Have fun&lt;/h1&gt;
&lt;p&gt;In retrospect I should have had an overall goal for my experimental games too. I never put an end date - it was just &lt;em&gt;new month = new game&lt;/em&gt; and in the end it wasn’t very inspiring to just churn out a game. It was as if I just had to make a game, it wasn’t something I wanted to do and it was almost as if it had become a chore.&lt;/p&gt;
&lt;p&gt;Mind you I’ve had lots and lots of fun making these games and the games who were the most fun to play were also the ones I had the most fun making. You could divide my games into three categories I think.&lt;/p&gt;
&lt;p&gt;The beginning: &lt;strong&gt;Fun&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2009/08/01/balls/&quot;&gt;Balls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2009/08/20/black_and_white/&quot;&gt;Black and White&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The middle: &lt;strong&gt;Really Fun&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2009/09/20/bugger/&quot;&gt;Bugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2009/10/13/menucity/&quot;&gt;MenuCity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2009/11/25/jonas_icecream_stand/&quot;&gt;Jonas IceCream Stand&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Failed game: The Zed Worker Party&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The end: &lt;strong&gt;Not so Fun&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2010/01/16/the_chronicles_of_bim_the_100_fake_afros/&quot;&gt;The Chronicles of Bim: The 100 Fake Afros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2010/02/28/a_geek_valentine/&quot;&gt;A Geek Valentine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The funny thing about this is that it works really really well both ways. Both how fun the games are and how fun I thought it was to make them. I think this is an indication for all you game developers out there: &lt;strong&gt;Have Fun&lt;/strong&gt;, not only will you live a happier and longer life but the game will also be a lot more fun!&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I’m not sure what the meaning of this post was. At first I wanted to state a new beginning for myself and then it turned out to a lessons-learned post… but whatever.&lt;/p&gt;
&lt;p&gt;I won’t be doing monthly experimental games for a while now, I’m happy with the results but I’m not at all motivated right now and I need a little break. I will continue my game making but it just won’t be exactly the same - maybe I will try to release a game, any game, each month or I’ll focus on making “real” games - games which are everything I want them to be, not just a proof of a concept. I guess that’s something that’s been bothering me about my experimental games - it feels like something is missing.&lt;/p&gt;
</content></entry><entry><title>No game this month</title><id>http://jonashietala.se/blog/2010/03/25/no_game_this_month/index.html</id><updated>2023-10-13T17:31:27+00:00</updated><link href="https://www.jonashietala.se/blog/2010/03/25/no_game_this_month" rel="alternate"/><published>2010-03-25T12:14:22+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Well here I am in the end of the month - without a game. It’s a failure I know but once again I lack inspiration and then it’s really hard to do something. Instead I’ve been thinking of something I could do that would make me wanna code like really bad again. I’m thinking of patching up this website, the forums are bugging me like hell as I didn’t write it, switching rendering framework for my games and just now today I’ve done a few &lt;a href=&quot;http://projecteuler.net/&quot;&gt;Project Euler&lt;/a&gt; challenges in Haskell which was pretty fun (but hard as I’m really bad with it).&lt;/p&gt;
&lt;p&gt;Next time I’ve got my sights on the &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt; which instead of a seven day game is a two day game! We’ll see how that’ll go.. If I have the power and the time to.&lt;/p&gt;
&lt;p&gt;I’ve also written a small piece about the Evolution of RTS games, heavily shortened to fit a perfect 5 pages a feat I’m quite proud of. Of course I wanted to write a hell of a lot more.&lt;/p&gt;
&lt;p&gt;In short: Not much has happened and not a lot is happening but we’ll see what the future has in store.&lt;/p&gt;
</content></entry><entry><title>Postmortem: A Geek Valentine</title><id>http://jonashietala.se/blog/2010/03/10/postmortem_a_geek_valentine/index.html</id><updated>2024-06-27T07:14:14+00:00</updated><link href="https://www.jonashietala.se/blog/2010/03/10/postmortem_a_geek_valentine" rel="alternate"/><published>2010-03-10T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Ah man the mush in my brain is finally letting go and I’m starting to feel this tiny little programming urge again… This time it’s not Haskell or a new experimental game that’s luring me on, no this time it’s me longing to create this &lt;em&gt;fantastic awesome epic&lt;/em&gt; RTS game. Sadly it’s a long way to go there…&lt;/p&gt;
&lt;p&gt;Anyway let’s get this going!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2010/02/28/a_geek_valentine/&quot;&gt;A Geek Valentine&lt;/a&gt; isn’t a good game by any means, it’s really nothing special. The gameplay sucked really bad. It’s kinda funny as I told Sundb00m this would be my greatest game gameplay wise. &lt;em&gt;Yeah right..&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;Hard Work Work!&lt;/h1&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/geek_workload.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;This is a small graph which shows how I’ve worked for a straight week from the 22th to the 28th. The Y-axis is hours and the X-axis is days. The labels are for either work or break and the height of the green peaks if you check it on the Y-axis is the sum of both green and red. Green is for hours where I actually worked and the red is for when I had a break. You know food, clipping toenails, reading manga and playing counter-strike.&lt;/p&gt;
&lt;p&gt;Total work time: ~25 hours&lt;br /&gt;
Total break: ~15 hours&lt;/p&gt;
&lt;p&gt;Weekend work: 13.8 hours&lt;br /&gt;
Weekend break: 8.3 hours&lt;/p&gt;
&lt;p&gt;The noteworthy thing about this is that I spend more than half of the whole week’s worth of time in the weekend and I probably got even more done during that time. I think it’s the whole deal with being chased with a the brutal thing of failure that motivates me.&lt;/p&gt;
&lt;h1&gt;Graphical Adoration&lt;/h1&gt;
&lt;p&gt;About the game let’s start with the positive stuff. I really like how the game looks, it actually looks pretty darn good (even though I forgot about the girls’ turning, now they’re just looking forward). I’m really improving in a graphical sense, something I thought impossible when I began this journey.&lt;/p&gt;
&lt;h1&gt;Do something you Like&lt;/h1&gt;
&lt;p&gt;Like with a Big L. I felt I had a really nice idea going for this one. In the end it looked and felt like a bad pacman clone but this wasn’t what I had in mind &lt;em&gt;at all&lt;/em&gt;. The idea was to build cool trap-combos sort of like in the &lt;em&gt;Epic Game Evil Genius&lt;/em&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/offsite/evil_genius_trap.jpg&quot; /&gt;
&lt;figcaption&gt;Here’s a plan for an über-trap in Evil Genius&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I really love Evil Genius and especially the base building but let’s face it - I failed. But the idea kept motivating me and it was really fun to try to make it happen.&lt;/p&gt;
&lt;h1&gt;A first small taste of an “AI”&lt;/h1&gt;
&lt;p&gt;How do the girls move? They have a 5x5 vision with a 2 radius (they’re in the middle) and they choose what to do. If they see the dude close to them either in front, left or right they’ll go there. Otherwise they’ll try to follow a path in front of them or to the left or right. Otherwise they’ll just go in a random direction.&lt;/p&gt;
&lt;p&gt;They are extremely stupid and you can trap them in a never-ending loop fairly easy and it’s a stretch to say they have intelligence but it was pretty cool to dip my hand into AI programming. I know it’s extremely shallow and bad and stuff but still it was pretty rewarding to see them actually move around on their own…&lt;/p&gt;
&lt;p&gt;I might actually develop this game further with special regard to AI. Change the core of the game so you can script both the player and the girls, just for laugh and giggles?&lt;/p&gt;
&lt;h1&gt;The game sucks but hey…&lt;/h1&gt;
&lt;p&gt;Yupp it’s not my best game, in fact I think it’s one of the worst. But I still like it a lot and my trap-building idea is still alive and I might develop the game more, improve the AI and focus on building traps (need a lot more cool traps damnet). Yes I think I might do that…&lt;/p&gt;
</content></entry><entry><title>March Theme: 10 seconds</title><id>http://jonashietala.se/blog/2010/03/02/march_theme_10_seconds/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2010/03/02/march_theme_10_seconds" rel="alternate"/><published>2010-03-02T11:57:37+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Well well here’s something interesting. &lt;a href=&quot;http://experimentalgameplay.com/blog/&quot;&gt;The Experimental Gameplay Project&lt;/a&gt; has given us a really interesting thing to focus on: Time. Like &lt;em&gt;Braid&lt;/em&gt;, it’s time for us to make something interesting with time itself. 10 seconds is the constraint and that’s not a lot, but perhaps enough?&lt;/p&gt;
</content></entry><entry><title>A Geek Valentine</title><id>http://jonashietala.se/blog/2010/02/28/a_geek_valentine/index.html</id><updated>2026-04-27T11:09:56+00:00</updated><link href="https://www.jonashietala.se/blog/2010/02/28/a_geek_valentine" rel="alternate"/><published>2010-02-28T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Yes! I made it! It’s 22:22 on the very last day of February and I’ve been programming virtually non-stop for the past two days, my brain feels like mashed potatoes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Geek Valentine&lt;/strong&gt;&lt;br /&gt;
&lt;img src=&quot;/images/games/thumbs/geek1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/geek2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/geek3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controls&lt;/strong&gt;&lt;br /&gt;
Steer with the arrow keys.&lt;/p&gt;
&lt;p&gt;Use spacebar to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build the time machine&lt;/li&gt;
&lt;li&gt;Buy and place traps (Just face an empty square and choose a trop on the top right)&lt;/li&gt;
&lt;li&gt;Sell traps (Face and click)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Story&lt;/strong&gt;&lt;br /&gt;
Well it’s Valentine’s Day and as the geek you are this is the worst day ever. Luckily you havean almost complete time machine hidden here in the grass and if you could complete it you’ll be safe for now! But beware… The girls are searching for you! Place traps and run away!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;About&lt;/strong&gt;&lt;br /&gt;
This game, as usual, was made for &lt;a href=&quot;http://experimentalgameplay.com/blog/&quot;&gt;The Experimental Gameplay Project&lt;/a&gt;. This time they asked for a short explanation on how the theme would fit together so here it is:&lt;/p&gt;
&lt;p&gt;Rejection + Valentine’s day = feelings hurt&lt;/p&gt;
&lt;p&gt;And you’re the one hurting all the girls’ feelings. Enjoy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credits&lt;/strong&gt;&lt;br /&gt;
&lt;em&gt;Music&lt;/em&gt;: Nighttime Falls, I’ll be Waiting for Her - &lt;a href=&quot;http://8bitcollective.com/members/ilocan18/&quot;&gt;ilocan18&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Sound effects:&lt;/em&gt; Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Rest:&lt;/em&gt; Me&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://codeberg.org/treeman/Rejection&quot;&gt;https://codeberg.org/treeman/Rejection&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>February gets Themed: Rejection</title><id>http://jonashietala.se/blog/2010/02/01/february_gets_themed_rejection/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2010/02/01/february_gets_themed_rejection" rel="alternate"/><published>2010-02-01T18:54:59+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;&lt;a href=&quot;http://experimentalgameplay.com/blog/&quot;&gt;The Experimental Gameplay Project&lt;/a&gt; has announced their next theme - and shame on me if I wouldn’t follow suite! With valentine coming up I might just have found a pretty nice idea, just now, writing this…&lt;/p&gt;
&lt;p&gt;Booyah!!&lt;/p&gt;
</content></entry><entry><title>Why is my file so huge?</title><id>http://jonashietala.se/blog/2010/01/24/why_is_my_file_so_huge/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/01/24/why_is_my_file_so_huge" rel="alternate"/><published>2010-01-24T17:39:55+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;My latest game was absolutely huge! And I’m not talking about the music (which was pretty huge too - roughly 20mb) but the little .exe file.&lt;/p&gt;
&lt;p&gt;It was 14,6mb!!&lt;/p&gt;
&lt;p&gt;Now every way you look at it, &lt;em&gt;that’s incredibly huge&lt;/em&gt;. It’s like comparing an ant to a human. Normally the little ant is the exe file which should be small, except that it’s not.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;http://www.kent.net/robotech/gallery/images/ant.gif&quot; /&gt;
&lt;figcaption&gt;Ants are powerful creatures&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Incredible I thought, what the heck did I do wrong? I mean my code isn’t really good but I never knew it was this horrible. So today I was determined to find the cause of this obscene mutant ant.&lt;/p&gt;
&lt;p&gt;I started out chopping off everything regarding exceptions, cause all c++ resources I’ve read say exceptions will take space like a mutant gremlin. Okay I thought and chopped away everything - but nothing happened.&lt;/p&gt;
&lt;p&gt;Now that’s weird, what happens if I scrap this.. and this.. It ended with me beginning a big revamp of my whole “engine”, or rather collection of stuff - nothing inherently wrong as it was badly needed - but nothing happened with my exe file! It was still almost 2mb big with basically only a hello world…&lt;/p&gt;
&lt;p&gt;Then it struck me! I had been using &lt;em&gt;-g&lt;/em&gt; with gcc and without any optimizing at all. When I turned on size and speed optimizations and scrapped the debugging the change was quite extraordinary.&lt;/p&gt;
&lt;p&gt;The mutant 14 637 kb was magically transformed to a more fitting ant size of 856 kb. I couldn’t save much of the total file size (23 254 kb -&amp;gt; 20 768 kb) so while I apologize for hogging your bandwidth, time and harddrive space I’m hoping you won’t be too mad at me.&lt;/p&gt;
</content></entry><entry><title>Postmortem: The Chronicles of Bim: The 100 Fake Afros</title><id>http://jonashietala.se/blog/2010/01/19/postmortem_the_chronicles_of_bim_the_100_fake_afros/index.html</id><updated>2024-06-27T07:14:36+00:00</updated><link href="https://www.jonashietala.se/blog/2010/01/19/postmortem_the_chronicles_of_bim_the_100_fake_afros" rel="alternate"/><published>2010-01-19T16:20:34+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;My first shooter! It’s working (although a friend got a null pointer error) so I’m a little happy.&lt;/p&gt;
&lt;h1&gt;The Time&lt;/h1&gt;
&lt;p&gt;I spent about 24 hours on this game. A whopping 30% was break time, mostly me eating, reading manga or playing games… This is proof of me being really lazy this month I think.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/afrograph.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;It’s pretty cool that everything regarding the scripting, loading the little levels I had from lua files and writing them took only a mere hour! I could have saved so much time if I would’ve scrapped the whole levels idea completely. (Levels are more than just the code it takes to load them from a file… a lot more)&lt;/p&gt;
&lt;h1&gt;Immersion&lt;/h1&gt;
&lt;p&gt;We all love big bangs and loads of stuff flying around on screen and sadly I didn’t deliver. I had all these ideas of pieces of dead afros flying around and dead things piling up on the ground which you’ll walk over… but I never did any of it which is sad cause it would be pretty damn cool.&lt;/p&gt;
&lt;p&gt;Another thing is the messages on the left side. Pretty cool - if they would actually say anything, but again I didn’t have time or the inclination or whatever to do anything with it…&lt;/p&gt;
&lt;p&gt;All we’re left with are the quakes which are kinda cool but they could do with some tweaking, maybe shorter and less frequent to really get the &lt;em&gt;omg&lt;/em&gt; effect.&lt;/p&gt;
&lt;h1&gt;Gameplay&lt;/h1&gt;
&lt;p&gt;It plays okay. Not a lot happening, it’s just a race against time. The immersion part would really hot up the gameplay cause really, it’s fun to blast things into the sky!&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;The game feels like it’s not finished. The whole afro thing was cool but it’s not revolutionary or anything different. It’s stuck in the middle between random ideas and mediocrity. Too bad.&lt;/p&gt;
</content></entry><entry><title>My Dream Game: The RTS</title><id>http://jonashietala.se/blog/2010/01/18/my_dream_game_the_rts/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2010/01/18/my_dream_game_the_rts" rel="alternate"/><published>2010-01-18T20:14:17+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Even if there are a million great games there’s one that has a very special place in my heart: &lt;em&gt;Supreme Commander&lt;/em&gt;. It’s not the game I’ve played the most and there might even be games which are better and more fun but &lt;em&gt;supcom&lt;/em&gt; was the game that introduced me to competitive gaming and it made it me feel like no game had done before. I took gaming seriously for once; sure I had played online with cs but I was never serious. I did nothing to improve myself, I didn’t really care - as long as I didn’t have 1-10 or a silly just-beginning-stat.&lt;/p&gt;
&lt;p&gt;Before supcom I always cheated my way through an RTS game (I still remember that &lt;em&gt;pepperoni pizza&lt;/em&gt; gives food and &lt;em&gt;quarry&lt;/em&gt; gives stone in age of empires) or just gave up when things got rough. Now I’m happy to give it my best just to beat guitar hero on expert and someday I’m sure I’ll do it! Getting beat down by a lame rush? Before I would just whine and shout “lamer” and throw out the game but instead I saved the replay, copied his moves and presto! Now I got to be the one who got shouted at!! And I can tell you - it felt a lot better…&lt;/p&gt;
&lt;p&gt;All this effort I put into the game really got me involved on a very different level than in any game before. I’d never even thought that &lt;em&gt;SimCity&lt;/em&gt;, the great 4th edition, was imbalanced. But when I think about it: the huge apartment-building with a couple of thousand inhabitants it always, always without fail clogged down all the transports even when I dedicated everything around it just for transport. Later I found out it was bugged and there’s a fix, somewhere, to download which will fix this and some other bugs. Now I started to find things I didn’t like in supcom, things that was… wrong. No matter what you did, and no matter what the really good guys did - you couldn’t beat a certain strategy. It ended with everyone playing the same faction, spamming the same units in game after game… Not really fun. I participated in discussions and believe it or not I think that I was right more often than not. I was improving!&lt;/p&gt;
&lt;p&gt;But hey! Why did they do this? What if they had done this instead? &lt;em&gt;If I had made a game it would have done this and thus been a lot better…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And here I am. I have this dream of making the best RTS game ever… Staying true to my play style from supcom: copy the good things from others, improve them and make them my own, my plan is to mix in the great things from all the RTS games I’ve played throughout the years. Obviously the most prominent would be supcom but also StarCraft, kknd, TA and CnC among others…&lt;/p&gt;
</content></entry><entry><title>The Chronicles of Bim: The 100 Fake Afros</title><id>http://jonashietala.se/blog/2010/01/16/the_chronicles_of_bim_the_100_fake_afros/index.html</id><updated>2026-04-27T11:09:35+00:00</updated><link href="https://www.jonashietala.se/blog/2010/01/16/the_chronicles_of_bim_the_100_fake_afros" rel="alternate"/><published>2010-01-16T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Aaah feels good having a game ready after the last month’s failure! This time it’s a small shooter.&lt;/p&gt;
&lt;h1&gt;The Chronicles of Bim: The 100 Fake Afro&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/afro1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/afro2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/afro3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Bullet masher - can you keep up with 100 enemies at the screen?&lt;/p&gt;
&lt;h1&gt;Instruction&lt;/h1&gt;
&lt;p&gt;W: up&lt;br /&gt;
A: left&lt;br /&gt;
S: down&lt;br /&gt;
D: right&lt;br /&gt;
mouse: shoot&lt;br /&gt;
space: leap into the sky!&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Music:&lt;/em&gt; The Last Prophecy - &lt;a href=&quot;http://synthr.wolfenhex.com/synthr.swf&quot;&gt;Matthew Le Blanc (SynthR)&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Sound effects:&lt;/em&gt; Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;Rest:&lt;/em&gt; Me&lt;/p&gt;
&lt;h1&gt;Source&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://codeberg.org/treeman/100-things&quot;&gt;https://codeberg.org/treeman/100-things&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><title>New Year, New Theme: 100 Things</title><id>http://jonashietala.se/blog/2010/01/01/new_year_new_theme_100_things/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2010/01/01/new_year_new_theme_100_things" rel="alternate"/><published>2010-01-01T21:39:52+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Happy New Year, Everyone! 2009 was great in many ways; I drove a submarine (yeah quite literally), I released 6 experimental games and recently I discovered the completely amazing game &lt;em&gt;Evil Genius&lt;/em&gt; but lets try to make 2010 even better!&lt;/p&gt;
&lt;p&gt;So let’s forget our small mishaps (yes I’m looking at &lt;a href=&quot;/blog/2009/12/04/december_theme_new_world_order&quot;&gt;you&lt;/a&gt; - December month without a game) and roll out a new theme. As usual I’m following The Experimental Gameplay Project’s theme which happens to be &lt;em&gt;100 Things&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;And Things could mean anything from sprites, sound effects to pixels or enemies.&lt;/p&gt;
</content></entry><entry><title>Now we have a Forum</title><id>http://jonashietala.se/blog/2009/12/21/now_we_have_a_forum/index.html</id><updated>2024-07-09T12:12:33+00:00</updated><link href="https://www.jonashietala.se/blog/2009/12/21/now_we_have_a_forum" rel="alternate"/><published>2009-12-21T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;In a burst of random energy I made a forum for madeoftree. Well okay I just made an awesome style for the awesome phpBB - the forum itself was up and running in say 10min and the rest of the latest days has been all about customizing. Now it’s finally &lt;em&gt;kinda&lt;/em&gt; complete so here it is (EDIT: it is now taken down)!&lt;/p&gt;
&lt;p&gt;Making it was the easy bit - now we need to generate some content! Where is the almighty sundb00m when we’re in a desperate need for spam?!&lt;/p&gt;
</content></entry><entry><title>Pushing toward Git</title><id>http://jonashietala.se/blog/2009/12/16/pushing_toward_git/index.html</id><updated>2026-04-27T11:10:29+00:00</updated><link href="https://www.jonashietala.se/blog/2009/12/16/pushing_toward_git" rel="alternate"/><published>2009-12-16T20:02:17+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The time has come; it’s time for me to move my source out in the open for the first time.&lt;br /&gt;
I present to you the source of the upcoming game (which has no name yet):&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Repository deleted, never became anything&lt;/em&gt;&lt;br /&gt;
&lt;a href=&quot;https://codeberg.org/treeman/&quot;&gt;Available on Codeberg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s nothing special really, if you want take a look at the code and help me improve it.&lt;/p&gt;
</content></entry><entry><title>Breaking the rule of three</title><id>http://jonashietala.se/blog/2009/12/14/breaking_the_rule_of_three/index.html</id><updated>2023-10-13T17:31:27+00:00</updated><link href="https://www.jonashietala.se/blog/2009/12/14/breaking_the_rule_of_three" rel="alternate"/><published>2009-12-14T11:49:31+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s pretty darn stressful making a game in a week, especially when you have this big great vision on how your game should be (which is &lt;em&gt;always&lt;/em&gt; grand). For me making &lt;em&gt;Balls&lt;/em&gt;, &lt;em&gt;Black and White&lt;/em&gt; and &lt;em&gt;Jonas IceCream Stand&lt;/em&gt; where truly stressful, &lt;em&gt;MenuCity&lt;/em&gt; and &lt;em&gt;Bugger&lt;/em&gt; not so much but still.&lt;/p&gt;
&lt;p&gt;This is why I’m giving me an early Christmas gift: &lt;em&gt;I won’t make the December game in a week&lt;/em&gt;. In fact I haven’t even logged the hours, I just work on it a little here and a little there and boy it’s nice not having to do something all the time.&lt;/p&gt;
&lt;p&gt;But there are downsides of course. I’m breaking my rules which is… bad and I don’t have that productivity boost I always get when under a deadline so now I’m pretty far behind.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/pow.png&quot; /&gt;
&lt;figcaption&gt;But the screenshot looks promising doesn’t it?&lt;/figcaption&gt;
&lt;/figure&gt;</content></entry><entry><title>The Arty Timeline</title><id>http://jonashietala.se/blog/2009/12/09/the_arty_timeline/index.html</id><updated>2023-10-13T17:31:27+00:00</updated><link href="https://www.jonashietala.se/blog/2009/12/09/the_arty_timeline" rel="alternate"/><published>2009-12-09T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;While working on &lt;a href=&quot;/blog/2009/12/01/postmortem_jonas_icecream_stand&quot;&gt;Jonas IceCream Stand&lt;/a&gt; I took a screenshot every day and I thought they looked pretty cool so here they are:&lt;/p&gt;
&lt;figure class=&quot;gallery&quot;&gt;
&lt;a href=&quot;/images/games/art/day1.png&quot;&gt;&lt;img src=&quot;/images/games/art/day1.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/games/art/day2.png&quot;&gt;&lt;img src=&quot;/images/games/art/day2.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/games/art/day3.png&quot;&gt;&lt;img src=&quot;/images/games/art/day3.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/games/art/day4.png&quot;&gt;&lt;img src=&quot;/images/games/art/day4.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/games/art/day5.png&quot;&gt;&lt;img src=&quot;/images/games/art/day5.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/games/art/day6.png&quot;&gt;&lt;img src=&quot;/images/games/art/day6.png&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/images/games/art/day7.png&quot;&gt;&lt;img src=&quot;/images/games/art/day7.png&quot; /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;And now I’m off with &lt;a href=&quot;/blog/2009/12/04/december_theme_new_world_order&quot;&gt;New World Order&lt;/a&gt; and (for once) I’ve got a really really good idea!&lt;/p&gt;
</content></entry><entry><title>December Theme: New World Order</title><id>http://jonashietala.se/blog/2009/12/04/december_theme_new_world_order/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2009/12/04/december_theme_new_world_order" rel="alternate"/><published>2009-12-04T18:10:06+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;The &lt;a href=&quot;http://experimentalgameplay.com/blog/&quot;&gt;The Experimental Gameplay Project&lt;/a&gt; drives on with the &lt;em&gt;Art Game&lt;/em&gt; theme which will last the rest of this year but that’s something we can’t accept! I’ve done my game and I didn’t force myself out from the Haskell world just to do nuthin so here’s a new little theme for me :)&lt;/p&gt;
&lt;p&gt;What does the U.S one dollar bill, the French Revolution and Zion have in common? It’s the conspiracy &lt;em&gt;New World Order&lt;/em&gt; of course!&lt;/p&gt;
&lt;p&gt;The paranoid can find it anything so this shouldn’t be a problem?&lt;br /&gt;
&lt;em&gt;Right?!&lt;/em&gt;&lt;/p&gt;
</content></entry><entry><title>Postmortem: Jonas IceCream Stand</title><id>http://jonashietala.se/blog/2009/12/01/postmortem_jonas_icecream_stand/index.html</id><updated>2024-06-27T07:14:58+00:00</updated><link href="https://www.jonashietala.se/blog/2009/12/01/postmortem_jonas_icecream_stand" rel="alternate"/><published>2009-12-01T15:03:04+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Ah my latest game &lt;a href=&quot;/blog/2009/11/25/jonas_icecream_stand/&quot;&gt;Jonas IceCream Stand&lt;/a&gt; is finished and up and running and I’m really proud of it! And thanks for the feedback guys, it’s always welcome.&lt;/p&gt;
&lt;p&gt;I spent almost exactly fifty hours on this game and that’s by far the most I’ve spent on a 7day project. To be honest it’s probably more but I’m not really good at logging all the hours…&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/icecreamgraph.png&quot; /&gt;
&lt;/figure&gt;
&lt;h1&gt;A Race&lt;/h1&gt;
&lt;p&gt;This game was a race against time from start to finish. I understood right from the beginning this wouldn’t be easy. Creating a whole GUI from scratch, composing animation and a focus on graphics(!). I’ve never done a GUI, it would be really easy with a decent framework for it… But I don’t have one for it so all the GUI code is &lt;em&gt;really&lt;/em&gt; messy and hard to maintain.&lt;/p&gt;
&lt;p&gt;I guess I’m learning the coding lessons the hard way. Keeping it structured and maintainable even, no, especially under pressure is extremely important. It’s a good thing I have a fast iteration cycle repeating itself for every new game I’m making.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/ops.png&quot; /&gt;
&lt;figcaption&gt;Heh&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Art&lt;/h1&gt;
&lt;p&gt;I keep saying it again and again but I’m not a graphics designer but I should stop saying that! Although not wonderful I think my games are looking good and this game is no exception. It’s certainly the most complex graphical wise.&lt;/p&gt;
&lt;p&gt;The fading effect on the sky was pretty cool, but it’s kinda crude and it doesn’t fit the overall theme very well. The theme has a few distinct colors with a little “childish” feel to them. I feel the fading adds a bit too many colors to it. But I do think the end points (in the middle of the night with all the stars and when it’s as light as possible) looks pretty good. And I’m not sure it was a very good idea to include a MenuCity silhouette in the background.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/skyatnight.png&quot; /&gt;
&lt;figcaption&gt;A beautiful night sky&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h1&gt;Gameplay&lt;/h1&gt;
&lt;p&gt;Sadly I don’t think the gameplay was one of my best. Sure the first five maybe ten minutes are a blast, they almost awoke my slumbering tycoon feelings. But the game is so badly balanced, it’s far too easy when you’ve passed a point in the game. The problem is that I balanced the game the last handful of hours on the very last day and that doesn’t work, not at all. A great gameplay needs to evolve, it can’t be created just there on the stop. Well that’s my experience at least.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I think the game is really great. Sadly it gets boring far too fast but it does have great potential. It’s almost worth given a remake as a “real” game.&lt;/p&gt;
</content></entry><entry><title>Jonas IceCream Stand</title><id>http://jonashietala.se/blog/2009/11/25/jonas_icecream_stand/index.html</id><updated>2024-06-27T07:33:51+00:00</updated><link href="https://www.jonashietala.se/blog/2009/11/25/jonas_icecream_stand" rel="alternate"/><published>2009-11-25T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Ahoy there! This time I’ll take you along for a ride with an arty Tycoon game.&lt;/p&gt;
&lt;h1&gt;Jonas IceCream Stand&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/ice3.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/ice1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/ice2.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
Get wild and become a Crazy Dealer of IceCream!&lt;/p&gt;
&lt;h1&gt;Instructions&lt;/h1&gt;
&lt;p&gt;It should be pretty self-explanatory, it’s a very simply tycoon game.&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Music:&lt;/em&gt;&lt;br /&gt;
All Around Us - &lt;a href=&quot;http://ericmaskol.com/&quot;&gt;Eric Maskol&lt;/a&gt;&lt;br /&gt;
I Will Always Look up to You - &lt;a href=&quot;http://www.stevechatterton.com/&quot;&gt;Steve Chatterton&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sound effects:&lt;/em&gt;&lt;br /&gt;
Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Rest:&lt;/em&gt;&lt;br /&gt;
Me&lt;/p&gt;
</content></entry><entry><title>An invisible Remake</title><id>http://jonashietala.se/blog/2009/11/02/an_invisible_remake/index.html</id><updated>2024-07-09T12:12:43+00:00</updated><link href="https://www.jonashietala.se/blog/2009/11/02/an_invisible_remake" rel="alternate"/><published>2009-11-02T22:51:36+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;What does a guy like me do when not working on a new game? Except living my life, being a coach for my little brother’s hockey team and eating strawberries? The last week or so I’ve been working hard with my webpage, yes this page. If you’ve visited my site before today you’ll know what I’m talking about.&lt;/p&gt;
&lt;p&gt;NOT&lt;/p&gt;
&lt;p&gt;There’s practically zero visible difference. You might notice the ‘Quick n Dirty File Download’ or the little line of text towards the bottom of the page, or even the ability for multiple tags! That’s kinda freaky stuff eh? And only +1 week to do that! :D&lt;/p&gt;
&lt;p&gt;The big thing was actually a complete rewrite of the whole site. From really bad and random spaghetti code I managed to produce some half-nice code. I wrote the site with &lt;a href=&quot;https://kohanaframework.org/&quot;&gt;Kohana&lt;/a&gt; which was a blast to use! If you’re making a page of some sort I can heartily recommend to give it a try.&lt;/p&gt;
&lt;p&gt;Soon it’s time for some game making again, I just need a good idea… hm.&lt;/p&gt;
</content></entry><entry><title>November Theme: Art Game</title><id>http://jonashietala.se/blog/2009/11/01/november_theme_art_game/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2009/11/01/november_theme_art_game" rel="alternate"/><published>2009-11-01T19:31:45+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Back over at &lt;a href=&quot;http://experimentalgameplay.com/blog/&quot;&gt;The Experimental Gameplay Project&lt;/a&gt; a new theme has come up. My last three themes haven’t been “my” themes: I’ve been following their lead and their themes and this month is no exception. This months’ apparently a big theme - &lt;strong&gt;Art&lt;/strong&gt;. It’s even a collaboration with a big art museum…&lt;/p&gt;
&lt;p&gt;The idea that games are art is an old one and there are a few games considered art - but it’s really hard to make an actual &lt;em&gt;art game&lt;/em&gt;. But I’ll try :)&lt;/p&gt;
</content></entry><entry><title>Postmortem: MenuCity</title><id>http://jonashietala.se/blog/2009/10/19/postmortem_menucity/index.html</id><updated>2024-06-27T07:14:50+00:00</updated><link href="https://www.jonashietala.se/blog/2009/10/19/postmortem_menucity" rel="alternate"/><published>2009-10-19T21:01:52+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Good times, good times. &lt;a href=&quot;/blog/2009/10/13/menucity//&quot;&gt;MenuCity&lt;/a&gt; has been out a while and thanks for all the positive and constructive feedback guys, it’s like my food doing this (programming is my air and the fun is the water… err). Anyway here’s the postmortem of my latest, and greatest, game.&lt;/p&gt;
&lt;p&gt;Let’s start with a hideous graph:
&lt;img src=&quot;/images/games/menucitygraph.png&quot; alt=&quot;&quot; /&gt;
God it’s ugly, but it works I guess. I spent about 32 hours on this game which is the most I’ve spent on an experimental game so far. The bulk of the game was actually done really, really quickly like the second day or so. All the gameplay was there and with pacemaker art too! The last 5 days of production was focused on polish, level design and art.&lt;/p&gt;
&lt;h1&gt;Art&lt;/h1&gt;
&lt;p&gt;I spent a lot of hours doing the arty business and I think the game looks really good. You’d think the art I have in the game would be doable in a lot fewer hours than I spent and you’re absolutely right. In the beginning I had a very different style in mind, it was supposed to be a dude trapped in a console (a beautiful one) with all the ground, the birds (yes birds!) and the blocks all comprised of numbers… But as I worked on it I switched more and more to the style I have now, albeit diverging from the theme but meh.&lt;/p&gt;
&lt;h1&gt;Production&lt;/h1&gt;
&lt;p&gt;These games I’m doing, they’re more about production than the games themselves I realize that now. Naturally I’m making the games how could they &lt;em&gt;not&lt;/em&gt; be about games?&lt;/p&gt;
&lt;p&gt;It’s just my impression but when I’m doing the games my focus is more on the process of making them, like planning on a free day which I can get zoned and only focus on the code, instead of playing around with “cool” stuff.&lt;/p&gt;
&lt;p&gt;This is good I’d say! But meh - we all like cool stuff, I mean it’s &lt;em&gt;cool!&lt;/em&gt; But making things happen, making things work on screen is way cooler than having them all set up in my head. And besides, my very best ideas (and games) have come when I focus on making them work instead of how cool they should be.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What is&lt;/em&gt; is always way cooler than &lt;em&gt;what should be.&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;The Game itself&lt;/h1&gt;
&lt;p&gt;Ahh the game… This one is my very best; it looks as good as &lt;em&gt;Bugger&lt;/em&gt;, it’s more addictive than &lt;em&gt;Balls&lt;/em&gt; and it’s even criminal to compare the levels to those of &lt;em&gt;Black and White&lt;/em&gt;! So what could be better? There are a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Horrible tutorial. I tried to redeem myself &lt;a href=&quot;/blog/2009/10/16/menucity_level_0_walkthrough/&quot;&gt;here&lt;/a&gt; but still.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Be able to move the camera for an overview of terrain. This I had planned, but I had other more important things to do and then I sorta forgot about it…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go back 5sec or a few moves. I mean how many times did you press the rest button? I know I did press it a dozen times too many.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move up with the side keys instead of having to switch, and slowing down, between up and side. This was suggested later and I don’t know why I didn’t think of this from the beginning :S&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repetitive sound. Well honestly I.. uh… yeah. The song is wonderful but some variation would be nice. And for the next game you need to stop and change the music from a menu, instead of the obscure console options. (&lt;code&gt;sound_enabled 0&lt;/code&gt; in console f1 or set in settings.ini)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Disappointing ending. This one is so true.. I might spoil this for you but the last level isn’t as demanding as the ultra hard ninth level. And there wasn’t even any ending credits or anything like that, almost like cleaning my room real good without anyone acknowledging it =(&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;MenuCity gave me a great ride, both developing it and playing it. And all the positive feedback doesn’t hurt my ego either ^^. There are things I dislike and annoy me but the games are getting better, I’m learning loads and the most important thing of all: It’s fun :)&lt;/p&gt;
&lt;p&gt;Yesterday I checked the date and there’s almost two weeks left until my next monthly experimental game! I might have to start another side project… hum hum…&lt;/p&gt;
</content></entry><entry><title>MenuCity: Level 0 Walkthrough</title><id>http://jonashietala.se/blog/2009/10/16/menucity_level_0_walkthrough/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2009/10/16/menucity_level_0_walkthrough" rel="alternate"/><published>2009-10-16T14:18:27+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It hasn’t even been a week since I released my latest game &lt;a href=&quot;/blog/2009/10/13/menucity//&quot;&gt;MenyCity&lt;/a&gt; and already so much positive feedback! I’m so thrilled :) However, all isn’t blue skies and nice sunshine. A lot of times the first question is: How do you play it? or How do you get past the first level? I admit yes, the tutorial is really bad…&lt;/p&gt;
&lt;p&gt;So this is me trying to redeem myself! I can’t go back and change the game and make a better tutorial - that would violate my limit of 7 days for each game so here’s the next thing. A nice walkthrough with a lot of pictures explaining the basics and it’ll show you how to actually complete the tutorial! :p&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/walkthrough/menucity_lvl0/1.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
This is you in the first level.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/walkthrough/menucity_lvl0/2.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
The big thing seems to be your ability to pick up stuff. Use the down key to pick up a block. The yellow stripey things are there to show you how many times you can pick up a block, so be careful.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/walkthrough/menucity_lvl0/3.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
You can climb one block up with the up key, naturally with or without a block on your head.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/walkthrough/menucity_lvl0/4.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
If you fall down you can’t get back up, here it’s okay - but don’t move too far to the left! Then you’ll get stuck and you can’t turn to drop the block.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/walkthrough/menucity_lvl0/5.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
Put down the block with the same key you picked it up - down. Notice that the block went all black and you can’t pick it up anymore. This will be the cause of some real frustration later on, trust me.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/walkthrough/menucity_lvl0/6.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
And here we go! All we have to do now is climb up that silly looking city silhouette and walk to the goal. And we’re done! =)&lt;/p&gt;
&lt;p&gt;Hopefully you’ll find this helpful if you’re stuck and dunno wtf this game is all about. If you want a walkthrough on some later levels just let me know and I’ll see what I can do.&lt;/p&gt;
</content></entry><entry><title>An intriguing new puzzle</title><id>http://jonashietala.se/blog/2009/10/13/an_intriguing_new_puzzle/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2009/10/13/an_intriguing_new_puzzle" rel="alternate"/><published>2009-10-13T23:40:09+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Here’s another game made for the &lt;a href=&quot;http://experimentalgameplay.com/blog/&quot;&gt;experimental gameplay project&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://frankforce.com/?p=1246&quot;&gt;Slidoku&lt;/a&gt; which is a sort of mix between Rubik’s cube and sudoku. I enjoy puzzles like those and I really enjoyed this one too - it took me a while to beat it but I just love the feeling when you do. If you like puzzles take a look, it’ll be worth it!&lt;/p&gt;
</content></entry><entry><title>MenuCity</title><id>http://jonashietala.se/blog/2009/10/13/menucity/index.html</id><updated>2024-06-27T07:34:13+00:00</updated><link href="https://www.jonashietala.se/blog/2009/10/13/menucity" rel="alternate"/><published>2009-10-13T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This game is called MenuCity and it’s a numbers game. Well that’s the theme anyway. The game pretty much held to what I planned for - except that it deviated from the theme -again- a bit.&lt;/p&gt;
&lt;p&gt;My game is very reminiscent of the old calculator classic &lt;em&gt;Block Dude&lt;/em&gt; made by Brandon Sterner. If you like that game, or any puzzle game for that matter, you’re gonna love this one.&lt;/p&gt;
&lt;h1&gt;MenuCity&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/menucity1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/menucity2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/menucity3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Instructions&lt;/h1&gt;
&lt;p&gt;Left/Right arrows - Move&lt;br /&gt;
Up arrow - Climb&lt;br /&gt;
Down arrow - Pick up/Put down&lt;br /&gt;
f1 - Secret dev console&lt;/p&gt;
&lt;p&gt;If you’re stuck this might help: &lt;a href=&quot;/blog/2009/10/16/menucity_level_0_walkthrough/&quot;&gt;Walkthrough Level 0&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;Music: The Year Before The War - &lt;a href=&quot;http://ericmaskol.com/&quot;&gt;Eric Maskol&lt;/a&gt;&lt;br /&gt;
Sound effects: Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
Rest: Me&lt;/p&gt;
</content></entry><entry><title>October theme says: Numbers</title><id>http://jonashietala.se/blog/2009/10/01/october_theme_says_numbers/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2009/10/01/october_theme_says_numbers" rel="alternate"/><published>2009-10-01T18:08:44+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;New month and a new theme. As with the two previous games I’m following &lt;a href=&quot;http://experimentalgameplay.com/blog/&quot;&gt;The Experimental Gameplay Project&lt;/a&gt; theme which this month is numbers. What’s it gonna be? A sudoku game or something more… thrilling? I’ll see what I can do :)&lt;/p&gt;
</content></entry><entry><title>Why make games</title><id>http://jonashietala.se/blog/2009/09/28/why_make_games/index.html</id><updated>2023-10-13T17:13:44+00:00</updated><link href="https://www.jonashietala.se/blog/2009/09/28/why_make_games" rel="alternate"/><published>2009-09-28T10:08:02+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Why did I start making games? Because I like to play them of course. Think of all the fantastic games; &lt;em&gt;Super Mario, Lemmings, Tetris, GTA, The Sims, Counterstrike, Theme Hospital, SimCity and Rollercoaster Tycoon&lt;/em&gt;… Damn - when you count them like this you’ll see how many great games there are out there. And I can honestly say each and every one of them has inspired me and made me wanna create something similar. &lt;strong&gt;No - something even better!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I also like to program, that’s almost a must if you should make a working game from scratch, so I figured why not use it to make something productive and hopefully something fun?&lt;/p&gt;
</content></entry><entry><title>Postmortem: Bugger</title><id>http://jonashietala.se/blog/2009/09/24/postmortem_bugger/index.html</id><updated>2024-06-27T07:15:09+00:00</updated><link href="https://www.jonashietala.se/blog/2009/09/24/postmortem_bugger" rel="alternate"/><published>2009-09-24T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;It’s time for the follow up on my latest game &lt;a href=&quot;/blog/2009/09/20/bugger//&quot;&gt;Bugger&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wow it seems like forever since I begun this monthly game business, but it’s only been two months since I first thought about this and here I am having finished my third game. I’ve really come a long way, in the beginning I though I’d only make state of the art crap games. Like I would struggle to even get a Tetris up and running. That’s partially why I decided to make &lt;a href=&quot;/blog/2009/08/01/balls//&quot;&gt;Balls&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway I started out with a small idea: speed-typing. It later turned out to be bugs you killed, but that’s of minor importance really. They were supposed to bind to the theme &lt;em&gt;Failure&lt;/em&gt; by letting the average gamer feel how a programmer fight for his life against bugs. Bugs are for those who don’t know errors in your program - they can be as simple as a wrong letter in the wrong place causing havoc in the game or a bigger thing like a fundamental flaw in your game. Think about the balls who got stuck in mid-air in &lt;em&gt;Balls&lt;/em&gt;. That’s a typical bug…&lt;/p&gt;
&lt;p&gt;If I followed the theme good or bad you be the judge. Personally I don’t think it was as clear as I’d want it to do but meh.&lt;/p&gt;
&lt;p&gt;The game itself took 25 hours to make - but more than 5 hours of them was me having a break.
Here’s a little jummy pie of what took time:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;/images/games/bugger-time-spent.png&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Compared to my two other games I spent a bigger part on both graphics and level design - and that was sourly needed imho. The “embedding scripting” part is where I built in the ability to build levels from lua. I think the result was really good and it saved a lot of time just being able to edit a file without having to recompile every single little change.&lt;/p&gt;
&lt;p&gt;You can make your own levels too, just open the “levels.lua” file in a text editor and make your changes. I won’t explain anymore since it’s really simple.&lt;/p&gt;
&lt;p&gt;I’m also using about 1/5 of my working time to rest. Jikes! That’s almost too much. But I dunno, it really hurts staring at your computer screen hour after hour. My longest session - without a break, even a bathroom one - was almost five hours. I totaled more than 10 hours that day I think.. As always I do the bulk of the work when I’m out of time. The last two days were responsible for at least 90% of the work!&lt;/p&gt;
&lt;p&gt;I guess you could say that’s a lesson: you’re most productive, and ambitious, when you’ve got a smoldering iron up your ass.&lt;/p&gt;
</content></entry><entry><title>Bugger</title><id>http://jonashietala.se/blog/2009/09/20/bugger/index.html</id><updated>2024-06-27T07:34:27+00:00</updated><link href="https://www.jonashietala.se/blog/2009/09/20/bugger" rel="alternate"/><published>2009-09-20T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Ahhh… Finally another game! Theme of this beauty is &lt;em&gt;Failure&lt;/em&gt; and your mission here is to avoid the bugs. As a programmer the fight with those nasty bugs are a daily occurrence and now I’ve brought you a chance to kill those nasties too!&lt;/p&gt;
&lt;p&gt;The gameplay wasn’t what I was planning on - yet again - but I’m actually quite content with the game. It’s able to grab your attention for at least a few minutes before loosing you and it’s absolutely the prettiest one I’ve ever made! Enjoy! ^^&lt;/p&gt;
&lt;h1&gt;Bugger&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/bugger1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/bugger2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/bugger3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Instruction&lt;/h1&gt;
&lt;p&gt;Type the text on the bugs to make them disappear, that’s all folks!&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;Music: Dare to Breathe - &lt;a href=&quot;http://tomfahy.org/&quot;&gt;Tom Fahy&lt;/a&gt;&lt;br /&gt;
Sound effects: Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
Rest: Me&lt;/p&gt;
</content></entry><entry><title>September theme: Failure</title><id>http://jonashietala.se/blog/2009/09/12/september_theme_failure/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2009/09/12/september_theme_failure" rel="alternate"/><published>2009-09-12T11:27:17+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’m out of the busy mode and here’s the new theme! I’ve got an idea and I’ll be beginning very soon I hope and again I’m following &lt;a href=&quot;http://experimentalgameplay.com/&quot;&gt;Experimental Gameplay Project’s site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s rock!!&lt;/p&gt;
</content></entry><entry><title>Going into Being Busy mode</title><id>http://jonashietala.se/blog/2009/08/25/going_into_being_busy_mode/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/25/going_into_being_busy_mode" rel="alternate"/><published>2009-08-25T20:13:09+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;I’m in the civil service atm and, sadly, we’re going to be extremely busy the coming… two months or something? So I can’t promise a game the next two months. Kinda beats the point of this site doesn’t it? I’m really sorry and that’s all I can say really…&lt;/p&gt;
&lt;p&gt;Hopefully I’ll get a week somewhere with enough spare time to create something. It’s a damn sure I’ll have to make a game about submarine warfare!!&lt;/p&gt;
</content></entry><entry><title>Postmortem: Black and White</title><id>http://jonashietala.se/blog/2009/08/21/postmortem_black_and_white/index.html</id><updated>2024-06-27T07:15:32+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/21/postmortem_black_and_white" rel="alternate"/><published>2009-08-21T10:10:33+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;All this time working on my latest game I thought it sucked and I was trying hard to make it to not suck. My spirit wasn’t high, just check &lt;a href=&quot;/blog/2009/08/19/incomplete_game_coming_up/&quot;&gt;this post&lt;/a&gt; and &lt;a href=&quot;/blog/2009/08/16/going_down/&quot;&gt;this&lt;/a&gt; but now when it’s done it’s like night and day, or like black and white! I’m damn happy I got it done!! Aah I’ll try to make this postmortem shorter than the last one… That was huge.&lt;/p&gt;
&lt;h1&gt;Lessons I’ve learned&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Levels take time&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I know you’re all disappointed by a measly three levels in the game and for that I’m sorry. I hadn’t set aside time for making the levels in my mental plan so when I ran over the time limit of 7 days I had to cut down on some stuff - this time it was the levels.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;A codebase rocks&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For my first game I had some basic code from older projects I used, like handling states, a small menu and a vector class among others and that saved me a whole lot of time. Now I had even more code so I got something on screen a lot faster and I could afford beginning with creating the dude and his animation (although I kinda overdid that) knowing I already had the basic foundation in place. Now I’m going to get my coding skillz up and the experience and this is another really big stone which will allow me to make bigger and more badass games later on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;It might not suck so hard after all…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the beginning I was pretty confident but I quickly lost that momentum and I thought a lot about how sucky this game is… It’s not polished, it’s not fun and the levels suck etc but it turned out to be okay! I have to stop being so damn negative! These are experimental games for crying out loud, they’re expected to fail once in a while and guess what? It doesn’t matter!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>Black and White</title><id>http://jonashietala.se/blog/2009/08/20/black_and_white/index.html</id><updated>2024-06-27T07:36:55+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/20/black_and_white" rel="alternate"/><published>2009-08-20T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Here it is at last! Boasting a unoriginal name, themed &lt;em&gt;Bare Minimum&lt;/em&gt;. My thoughts where to create a game where graphics where included into the gameplay but sadly it didn’t come out nearly as good as I expected it too.&lt;/p&gt;
&lt;p&gt;Yes I know there are a lot of things bad and wrong with this game, but this is a competition with myself to create a game in only seven days and you can’t always polish the games like your heart tells you to do.&lt;/p&gt;
&lt;h1&gt;Black and White&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/bw1.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/bw2.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/bw3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Instructions&lt;/h1&gt;
&lt;p&gt;Move left and right with the arrows, jump with space and change the blocks with enter. Esc into the menu and there you can enter a highly advanced (not) level editor to change the levels however you want with left and right mouse.&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;Music: What we take to the grave - Tom Fahy&lt;br /&gt;
Sound effects: Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
Rest: Me&lt;/p&gt;
</content></entry><entry><title>Incomplete game coming up</title><id>http://jonashietala.se/blog/2009/08/19/incomplete_game_coming_up/index.html</id><updated>2023-10-13T17:31:27+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/19/incomplete_game_coming_up" rel="alternate"/><published>2009-08-19T19:24:20+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Man I’m far too much of a perfectionist, with this mentality I’ll never get anything done - seriously. I spent far too many hours, even days, figuring out in my mind how the game should be and I started off going for nothing less than just that. But it turned out to be a lot harder and a lot bigger but still I couldn’t let it go and start over with something new, something fresh.&lt;/p&gt;
&lt;p&gt;I wonder isn’t this something very common? Not just in game development but for everything in life; we always stick with our idea of perfection and stuff that we’re familiar with, trying hard not to do something different and unfamiliar. I can honestly say I’ve tried to make something fresh and different but maybe that’s my problem. I’m trying too hard and when it’s impossible I still won’t let it go… Just maybe it might work if I do it like this… maybe?!&lt;/p&gt;
&lt;p&gt;No this month’s game is going to be crap, I can see it. Polish, which I believe is the single most important ingredient in a game, is non-existent. And worse yet, the gameplay is bad - in fact it’s even worse, it’s unplayable and boring! Never mind that I’ll give myself tomorrow to give the game a bit more love in the hope of making it just a tiny bit less sucky.&lt;/p&gt;
&lt;p&gt;What do you think; should I release the game - no matter what - after one week and ignore my need for perfection or should I give the unfinished and “bad” game more love so it might be a little better and a bit more fun to play?&lt;/p&gt;
</content></entry><entry><title>Going down</title><id>http://jonashietala.se/blog/2009/08/16/going_down/index.html</id><updated>2023-06-09T09:57:57+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/16/going_down" rel="alternate"/><published>2009-08-16T16:32:02+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Ah my first game was so painless so I thought I could do any game I could imagine! Shooters, and mario bros kinda stuff. Well now I’m not so upbeat anymore, I’ve worked on this game for 7 days now and it’s not playable at all. With seven days I don’t mean a week, I’ve had a big break in the middle with no reason at all!&lt;/p&gt;
&lt;p&gt;Anyway I realize I can’t make the one week mark… which sucks… and the game isn’t looking or feeling the way I want it too but I will release it when I’ve made it slightly less sucky.&lt;/p&gt;
</content></entry><entry><title>August theme: Bare Minimum</title><id>http://jonashietala.se/blog/2009/08/04/august_theme_bare_minimum/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/04/august_theme_bare_minimum" rel="alternate"/><published>2009-08-04T12:50:20+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;This time I’ll be following &lt;a href=&quot;http://experimentalgameplay.com/blog/2009/08/and-the-theme-of-august-is/&quot;&gt;my inspiring site&lt;/a&gt; and declare &lt;strong&gt;Bare Minimum&lt;/strong&gt; as the theme for my next game. This could really be anything, from graphics to user interaction… But I’ve got an idea. It’ll be a real challange for me to make but hopefully I’ll have a game in a few weeks time.&lt;/p&gt;
</content></entry><entry><title>Postmortem: Balls</title><id>http://jonashietala.se/blog/2009/08/04/postmortem_balls/index.html</id><updated>2024-06-27T08:00:35+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/04/postmortem_balls" rel="alternate"/><published>2009-08-04T12:33:38+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;So it’s been what? Two, three years since I discovered the art of programming and I haven’t made one single game?! Well now I’m not counting the visual basic nightmare &lt;em&gt;mastermind&lt;/em&gt; I made a long time ago but a real game. Whatever that means. I’ve had these monster-projects;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Point and click monkey island style adventure game&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The beginning c++ adventure for me. Kinda harsh start up don’t you think? I thought so too - it never got anywhere near completion or playability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Another heavy game&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Think fully destructible environment. Need I say more?… No.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The Game Engine&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The project everyone dreams of making games ends up doing and either discover it didn’t amount in anything playable, which I did, or you’ll end up thinking creating games is &lt;em&gt;extremely&lt;/em&gt; hard and it’ll take years for just a small game.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The Dream project&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I’ve been thinking of making a few posts about the games in my dreams. Which I’ll most certainly complete! Sometime… Maybe…?!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Somewhere about now I got interested in Indie games. I think &lt;a href=&quot;http://2dboy.com/&quot;&gt;World of Goo&lt;/a&gt; was the first but I’m not really sure. Maybe &lt;a href=&quot;http://www.armadillorun.com/&quot;&gt;armadillo run&lt;/a&gt; or &lt;em&gt;bridge builder&lt;/em&gt;? Damn! I couldn’t even google the link to &lt;a href=&quot;http://www.google.com/#hl=en&amp;amp;q=pontifex+3&amp;amp;aq=f&amp;amp;oq=&amp;amp;aqi=g2&amp;amp;fp=flbC24gbdiA&quot;&gt;bridge builder aka pontifex 3&lt;/a&gt; - all I found was a thousand torrent sites…&lt;/p&gt;
&lt;p&gt;But what I did find was &lt;a href=&quot;http://www.kloonigames.com/blog/&quot;&gt;kloonigames&lt;/a&gt;, some guy who did the same thing I’m doing. Or I’m doing the same as him: following the footsteps of the &lt;a href=&quot;http://experimentalgameplay.com/&quot;&gt;Experimental Gameplay Project&lt;/a&gt;. Making a game in 7 days, something surely impossible, and I haven’t even made any game before! Oh crap! But as Petri (kloonigames dude) so elegantly put it:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;My experiences told my that creating, even a small, game takes months, if not years. So to do it in 7 days seem frightening. And not only the code, but graphics, music, sound, levels and all things included. I shit my pants even thinking about it and almost gave up. Luckily I realized that the worst thing that could happen (beside shitting my pants) was wasting a week of my life. I could do that easily with a Buffy the Vampire Slayer marathon.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And here’s a summary of my first &lt;em&gt;ever&lt;/em&gt; game &lt;strong&gt;Balls&lt;/strong&gt;. It’s available &lt;a href=&quot;/blog/2009/08/01/balls//&quot;&gt;here&lt;/a&gt; for download.&lt;/p&gt;
&lt;h1&gt;The Good&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;I got it done!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It seemed impossible and it scared the hell out of me. But I made it!! Aaah… It feels so good right now. And the game is actually pretty fun! It doesn’t suck, it doesn’t crash (but it’s a bit buggy) and I can sort of say I managed to stick to my theme &lt;em&gt;Addictive Gaming&lt;/em&gt;. Now with this over with I can focus on my next game. Not just now but in a while, now I’m confident to try new, bigger and hopefully better things and I know I can pull it off!&lt;/p&gt;
&lt;p&gt;I’m on top of the world! Nothing is impossible! Superman and Neo - you’re just sooo jealous right now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;It didn’t even take long…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I end up using &lt;a href=&quot;http://www.kloonigames.com/blog/general/timelog&quot;&gt;timelog&lt;/a&gt; from kloonigames to track my time. The game took &lt;strong&gt;25,5 hours to make&lt;/strong&gt;, but I spent 7,5 hours of that time on a break! Either reading manga, playing cs or just surfing around and chatting. This isn’t the time to nag about my lack of concentration and that I’m lazy, this is where I realize I didn’t even work myself to death making the game. I could afford a break here and there, and now when I think about it they were really necessary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Pressure is good&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I did manage to implement some physics and collision detection, even though it’s really simple. This was a first for me and I did it under a tight schedule! A coincidence? I don’t think so, a small amount of pressure is really really good. It is during these times I’m most productive and I really do get things done &lt;em&gt;if I have to&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;The Bad&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The motivation didn’t stick&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Although I made the game and it was pretty good I didn’t even remotely invest as much time in it as I could - and I don’t know why. I lost that super motivation pretty early in development and when I hit a bug or something that needed a lot of changing to implement I usually cut corners or just ran away screaming.&lt;/p&gt;
&lt;p&gt;Is this the every day life of a developer? If it’s this though to get motivated wonder how you can motivate yourself working on a shitty project?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;The Ugly&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The code&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Wow - I’m never showing the source of this to anyone! I tried doing the things which would make the game nearest completion, I did cut some corners but in the end the job is done. But it’s really ugly and before reusing the code I’ll need to clean it up a lot!&lt;/p&gt;
&lt;p&gt;What’s that smell…? It stinks of smelly code!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><title>Balls</title><id>http://jonashietala.se/blog/2009/08/01/balls/index.html</id><updated>2024-06-27T07:37:05+00:00</updated><link href="https://www.jonashietala.se/blog/2009/08/01/balls" rel="alternate"/><published>2009-08-01T00:00:00+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Here’s my first ever experimental game! The theme was &lt;em&gt;Addictive Gaming&lt;/em&gt;. My first thought was oh god I’ll be making another tetris clone but the end result turned out a bit different. I’m not sure it’s very addictive but it’s actually okay! =D&lt;/p&gt;
&lt;p&gt;Balls is a game about… balls. Well it’s all in 2D so maybe Circles would be a better description but I don’t think that captures the attention enough.&lt;/p&gt;
&lt;p&gt;I didn’t think this was possible but here it is! My very first jewel =)&lt;/p&gt;
&lt;h1&gt;Balls&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/images/games/thumbs/balls1.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/balls2.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;/images/games/thumbs/balls3.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Instructions&lt;/h1&gt;
&lt;p&gt;Well… There’s nothing to it really. Move the mouse over the balls to make them shrink, survive until the top is filled with balls.&lt;/p&gt;
&lt;h1&gt;Credits&lt;/h1&gt;
&lt;p&gt;Music: Markovich/A.M.P. - Twisted in flight&lt;br /&gt;
Sound effects: Random from &lt;a href=&quot;http://www.freesound.org/&quot;&gt;freesound&lt;/a&gt;&lt;br /&gt;
Rest: Me&lt;/p&gt;
</content></entry><entry><title>My first theme: Addictive Gaming</title><id>http://jonashietala.se/blog/2009/07/25/my_first_theme_addictive_gaming/index.html</id><updated>2023-10-13T17:30:56+00:00</updated><link href="https://www.jonashietala.se/blog/2009/07/25/my_first_theme_addictive_gaming" rel="alternate"/><published>2009-07-25T11:41:39+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;In true experimental spirit I’ll now announce the theme for my first game: &lt;em&gt;&lt;strong&gt;Addictive Gaming&lt;/strong&gt;&lt;/em&gt;. I won’t be following the lead from the &lt;a href=&quot;http://experimentalgameplay.com/&quot;&gt;Experimental Gameplay Project’s site&lt;/a&gt; but I will follow their three laws (7 days, alone, themes).&lt;/p&gt;
&lt;p&gt;Puh… my first game! Wish me luck =)&lt;/p&gt;
</content></entry><entry><title>The first (worst) post</title><id>http://jonashietala.se/blog/2009/07/21/the_first_worst_post/index.html</id><updated>2024-07-09T12:13:03+00:00</updated><link href="https://www.jonashietala.se/blog/2009/07/21/the_first_worst_post" rel="alternate"/><published>2009-07-21T13:34:38+00:00</published><content xml:base="https://www.jonashietala.se/" type="html">&lt;p&gt;Well, here it is: The opening post. What will come here? Here’s where I’ll outline what the blog will be about and maybe, if I’m dedicated, it won’t die before Christmas you think.&lt;/p&gt;
&lt;p&gt;And sure, you’re right. I will run away to the corner in about two and a half months crying I never got the traffic I’m fantasizing about but I can try to summarize the site in one sentence: &lt;strong&gt;I’m going to make a themed game every month&lt;/strong&gt;. There, I’ve said it. Tired and scared of wasting my time with a monster-project I’ve decided to use the &lt;a href=&quot;http://www.gamasutra.com/features/20051026/gabler_01.shtml&quot;&gt;experimental project model&lt;/a&gt;. Basically I’m going to make a game in 7 days, kinda like God made the world. And I’m alone making these games, all the gfx, the sound and the code.&lt;/p&gt;
&lt;p&gt;If this got you interested check back regularly for some cool (I hope) games and read my posts.&lt;/p&gt;
</content></entry></feed>