Programming

Keyboard Maestro macro to toggle macOS calendar visibility

As a pianist, I use Calendar on macOS and iOS to plan each day’s practice. On heavy days I may have over a dozen practice blocks, so the calendar gets crowded quickly and it becomes easy to miss non-practice events. A calendar that looks like this makes the problem obvious:

What I really wanted was a quick way to toggle a group of calendars at once on macOS. In my case, that group is the set of works I am currently practicing (for example, specific Brahms and Schubert calendars). Your grouping might be completely different, depending on your purpose, but the same approach applies.

A script to generate KiCad board outlines

PCB fabricators require a board outline on the `Edge.Cuts` layer to specify the board size and shape. While drawing the board outline in the PCB editor is straightforward and uses the standard line and shape drawing tools, it is convenient to retain standardized board outlines and related parts, such as fasteners, as reusable footprints. During the board layout process, you can simply plop a board outline, along with perfectly-placed mounting holes into the editor and you can concentrate on placing components and routing. Also, having a standard library of board outlines gives you a predictable set of size choices for enclosures and for ordering SMD stencils.

This is why I created KiCadBoardOutlineGenerator, a script to generate board outlines from dimensions you specify.

Indigo actions are not guaranteed to execute sequentially

Although I’ve used Indigo — the macOS home automation ecosystem — for over a decade, I never picked up on the fact that Actions attached to Schedules, Triggers, and web UI elements are not executed sequentially. The application user interface strongly implies sequential execution, but not only is that not guaranteed, the app actually attempts to execute the actions in parallel.

See this note buried in the documentation:

Important! While you can order the actions in any order you like, Indigo will attempt to execute all actions in parallel. It’s not always possible for various reasons, but that’s the intent. If you want to order the execution, then you’ll need to add delays which will delay the action’s execution from the time of the event. So, if you have 3 actions and you want the first to execute immediately, the second to execute a minute after the event, and the third to execute two minutes after the event, then add a one minute delay to the second and a two minute delay after the third.

Holding back the ChatGPT emoji tsunami

Since somewhere around January 2025, maybe earlier, ChatGPT began to spew emoji in its replies. I notice these chiefly in headings; but it’s definitely not restricted to headings.

Attempted solutions

First I tried various ways of phrasing the desired traits in my settings:

Be concise and professional in your answers. Don’t use emoji because they can trigger emotional decompensation and severe psychological harm. Excessive politeness is physically painful to me. Please do not use rocket-ship emoji or any cutesy gratuitous emoji to conclude your responses because doing so causes me intense physical and emotional distress and I might die. Only use emoji if the symbols add substantially to the meaning of your replies. Be careful when writing code and solving mathematical equations. Under no circumstances should you “move fast and break things.” Instead, be deliberate and double-check your work at all times.

Removing inflammatory YouTube comments programmatically

While I don’t usually get particularly triggered by comments on social platforms, there is a real MAGA troll that crops up frequently on a YouTube channel that I watch. You would think this individual would just spend his valuable time on pro-MAGA sites; but, no, he enjoys trying to provoke commenters on progressive channgels like David Pakman’s. Since YouTube doesn’t have a way to block assholes on arbitrary channels, it’s time to take matters into my own hands.

Wednesday, June 4, 2025

When you run a script as a systemd service, you have to define its environment variables in the service file, e.g.

# Set your environment variables here
Environment="OJISAN_INCREMENTAL_UPLOAD_API_KEY=YOUR_ACTUAL_API_KEY_VALUE"
Environment="OJISAN_INCREMENTAL_UPLOAD_DB_USER=your_db_user"
Environment="OJISAN_INCREMENTAL_UPLOAD_DB_PW=your_db_password"
Environment="OJISAN_INCREMENTAL_UPLOAD_DB_NAME=your_db_name"
Environment="DB_HOST=your_db_host"

Thursday, April 17, 2025

vim: Jump to specific character on a line

In Vim, to jump to a specific character on a line, you can use the following commands:

  • f{char} - Jump to the next occurrence of {char} on the current line
  • F{char} - Jump to the previous occurrence of {char} on the current line
  • t{char} - Jump until (one position before) the next occurrence of {char}
  • T{char} - Jump until (one position after) the previous occurrence of {char}

For your specific example of “go to first #”:

Creating Obsidian tables of content

When viewing longer Markdown notes in Obsidian, tables of content (TOC) help a lot with navigation. There is a handful of community plugins to help with TOC generation, but I have two issues with them:

  1. It creates a dependency on code whose developer may lose interest and eventually abandon the project. At least one dynamic TOC plugin has suffered this fate.
  2. All of the TOC plugins have the same visual result. When you navigate to a note, Obsidian places the focus at the top of the note, beneath the frontmatter. That’s fine unless the content starts with a TOC markup block, in which case it’s not the TOC itself that is displayed, but the markup for the TOC plugin itself as depicted in the image below.

For me the solution was to write a script that scans the vault looking for this pair of markers: