Recent Posts (all)

Linking Directly to Web Page Content with Typinator

Recently, the major browsers introduced the capability to go to a webpage highlighting and scrolling to a particular piece of text. Once you see it in action, it really is neat.

They syntax is <original_url>#:~:text= followed by the URI encoded text you want to highlight, like https://blog.lanzani.nl/2024/who-will-speak-up-for-free-speech/#:~:text=Economist (you can click on it to see for yourself).

Typing the whole thing is, however, cumbersome, so I resorted to Typinator to automate some of it, creating a snippet (bound to ;frag) like this:

1{/JavaScript
2let text = encodeURIComponent("{clip}")
3let safari = Application("Safari");
4safari.documents[0].url() + "#:~:text=" + text
5}

The way I engage with it is simple: on a page, I copy some text, and then, in another application (it doesn’t work in Safari—although with some tweaks it might) I type ;frag and the URL including the #:~text=something appears instead.

The script works as follows:

  1. Line 2 expands the clipboard and URI encodes it (for example, replacing spaces with %20).
  2. Line 3 grabs an object that lets you manipulate the Safari application. This Javascript system built into the system is one of those big details in macOS that sets it apart from the competition, in my opinion.
  3. Line 4 gets the URL of the active tab, and appends first #:~:text= and then the encoded text.

That’s it. Simple and effective.

Posted on 15 Nov 2024

Who will speak up for free speech

As Brazil bans Elon Musk’s X, who will speak up for free speech?

A thoughtful, as often, article by the Economist on how the usual defenders of free speech (the liberals) are not defending it, leaving the task to the (far) right.

The killer quote:

Our long-standing position is clear: only with the freedom to be wrong can societies advance slowly towards what is right. What has changed is that today the loudest objections to the crackdown on free speech come from right-wingers such as Elon Musk, X’s boss, while many self-described liberals applaud what they see as a blow against Trump-supporting billionaires. As speech becomes a culture-war battleground, those who disagree with the politics of Mr Musk and his allies have become relaxed about the onslaught.

Posted on 05 Sep 2024

Binepad BNK8 Macropad

Beautiful macropad by Binepad. Imagine the possibilities when customizing the firmware via Via and QMK!

A render of the Binepad BNK8 Macropad
Posted on 03 Sep 2024

Trust local caddy certificates on macOS

Up to today, I’ve been bothered by having local https websites served by Caddy, whose certificates were not trusted by macOS. Today, I rectified it.

For macOS (and Safari) to trust what Caddy deploys locally, I had to:

A screenshot of a certificate open with Keychain Access

Then, all the local websites Caddy is serving will be trusted automatically.

Posted on 30 Jun 2024

A culture of brutal honesty

The New York Times on how the AI pin flopped

Insightful linked post from John Gruber on why the AI pin flopped. This bit stood out to me as particularly insightful:

It is the kiss of death for any endeavor, creative or technical, to have a culture where brutally honest internal criticism is not welcome, especially when it goes up the chain. In fact it needs to be the expectation, if you’re pursuing excellence.

Posted on 07 Jun 2024

Docker_isbg

I recently started using docker_isbg, a container bundling isbg and imapfilter to filter out spam from a remote IMAP server.

Getting started is relatively straightforward and relies mostly on a JSON configuration file such as

{
  "server": "mail.somewhere.com",
  "username": "somebody@somewhere.com",
  "password": "Password",
  "isGmail": "no",                        //Optional; Default = no
  "spamSubject": "[SPAM?]",               //Optional;
  "report": "yes",                        //Optional; Default = no
  "spamLifetime": 30,                     //Optional;
  "folders": {
    "spam": "Spam",
    "ham": "ham",                         //Optional;
    "sent": "Sent",                       //Optional;
    "inbox": "INBOX"
  }
}

After setting it up to run on a non-Gmail email host, however, I noticed the logs were complaining that isbg couldn’t find Gmail-specific folders. That meant that, somehow, my configuration was telling isbg that I was on a gmail host, even though the line"isGmail": "no" was in my config.

After some looking around, I saw the offending piece of code in docker_isbg (newlines added for clarity):

if( confLoader.tableHasKey( config, "isGmail" ) 
    and config.isGmail ) 
    then 
      gmailOption = " --gmail" 
    else 
      gmailOption = "" end 

The code checks whether config (which is a dictionary-like object resulting from the parsing of the above JSON) has a isGmail key, and whether it is set to anything: it can be yes, no or any other string and it will pass the --gmail option to isbg.

To fix it, I opened a PR that changes the above lines to

if( confLoader.tableHasKey( config, "isGmail" ) 
    and config.isGmail == "yes" ) 
    then 
      gmailOption = " --gmail" 
    else 
      gmailOption = "" end 

While the project seems to be mostly abandoned so I don’t expect a prompt merge, there’s another easy fix: changing the "isGmail": "no", line to "isGmail": false in the configuration file as in that case the config.isGmail code will evaluate to false.

Posted on 05 Apr 2024

Start using ddclient

For more than 10 years, I’ve been a happy client of Tweak (how long will that link work?). One of the many features it offered was a fixed IP address.

Now that I’m forced to switch to Odido, I will lose this affordance, which serves me greatly whenever I need to connect to my VPN at home. In fact, my phone and laptop are configured to just connect to a subdomain of lanzani.nl, which pointed to my home address, and that address never changed.

I then started looking for ways to update my IP address automatically. Luckily, there seems to be a service that’s been designed for this, ddclient that I’ve set up in my home server as follows:

# ddclient.conf
daemon=600
use=web
protocol=porkbun
apikey=APIKey
secretapikey=SecretAPIKey
subdomain.lanzani.nl
services:
  ddclient:
    image: lscr.io/linuxserver/ddclient:latest
    container_name: ddclient
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - /path/to/code/ddclient:/config
    restart: unless-stopped
[migrations] no migrations found
usermod: no changes
───────────────────────────────────────
      ██╗     ███████╗██╗ ██████╗
      ██║     ██╔════╝██║██╔═══██╗
      ██║     ███████╗██║██║   ██║
      ██║     ╚════██║██║██║   ██║
      ███████╗███████║██║╚██████╔╝
      ╚══════╝╚══════╝╚═╝ ╚═════╝
   Brought to you by linuxserver.io
───────────────────────────────────────
To support LSIO projects visit:
https://www.linuxserver.io/donate/
───────────────────────────────────────
GID/UID
───────────────────────────────────────
User UID:    1000
User GID:    1000
───────────────────────────────────────
[custom-init] No custom files found, skipping...
Setting up watches.
Watches established.
[ls.io-init] done.
/config/ddclient.conf MODIFY 
ddclient has been restarted
Setting up watches.
Watches established.
SUCCESS:  updating ipv4: skipped: subdomain.lanzani.nl address was already set to ...

That’s it. Just a few lines of code, and the problem is gone!

Posted on 26 Mar 2024

Bitten by timezones and Docker

I am building a Telegram chatbot to remind me to take out the trash.

I’m overengineering it, so of course it has Docker and a (sqlite) database.

One component of the chatbot does an hourly check. If tomorrow the trash will be collected, and the current time is later than the time I want to receive the notification (and if I haven’t been notified today), I should get a message.

However, I was not getting the messages. The code seemed solid

SELECT 
  user 
FROM
  users
WHERE
(
  TIME('now', 'localtime') > TIME(time_of_day) AND
  DATETIME('now', 'localtime', '-1 day') >= 
  DATETIME(last_executed_run, TIME(time_of_day))
)
OR
  last_executed_run IS NULL

Worse of all, when I was running on the Docker host, I would get notified at the right time.

It turns out Docker doesn’t respect the host timezone, but you need to be explicit about it, adding a TZ environment variable (in my case TZ=Europe/Amsterdam).

Posted on 15 Mar 2024

Automatically add images for Open Graph in Hugo

While using a static site generator is a low-maintenance endeavor, it also means that complex requirements need to be coded if nobody has done it before. Today, I automated image previews that can be used to display a nice preview through for Open Graph (and Twitter cards!).

The Open Graph protocol enables any web page to become a rich object in a social graph. My blog, however, is text-heavy and often misses the images, so I had to come up with something else.

In the end, I settled with a solution (code below) that displays a static image with some text on top, including the title, a snippet of the blog, and the URL.

The snippet can be explicitly set in the front matter with the snippet key, otherwise it will take the first characters of the post itself.

To make it all work, you need a couple of things in your Hugo theme

├── assets
│  ├── Inter-Medium.ttf
│  ├── Inter-SemiBold.ttf
│  └── og_base.png
├── layouts
│  ├── partials
│  │  ├── opengraph.html
   

Here, og_base.png is just the empty image used to write text on, like:

The open graph base image

The fonts are just the fonds, and opengraph.html contains:

In the, then, every blog post will be accompanied by an image as

The rendered open graph image
Posted on 14 Mar 2024

Men Children

An interview with Lyz Lenz

In the quoted toot, Lyz Lenz offers the wrong solution to a wide-spread societal problem: men who have remained children.

Our society tries to delay or prevent people growing up: making irreversible decisions, taking responsibility, caring for someone else more than for yourself, suffering.

Women are forced to much of the above when they become mothers (an irreversible decision, they take responsibility for the newborn, they will defend their child with their life, and laboring is a lot of suffering).

Men, on the other hand, can skip everything when they become fathers: they can leave and, when they stay, they can pretend to continue as nothing happened.

The tragedy is a that the situation creates a vicious cycle: as the father is absent or doesn’t take up his duties as a father, the mother protects her child even more, making it hard for the child to grow.

Posted on 23 Feb 2024
1/11