Off to breakfast this morning.

Met some locals on the way.

Day One needs a “this time one day ago” section, where you look at the entries from yesterday, realised you’ve made all these spelling and grammatical errors, and you go ahead and fix them. I sure know I can make use of such a feature.
Adding Copy-To-Clipboard And Layout Changes In Dynamo-Browse
Spent some more time on dynamo-browse this morning, just a little bit.
Got one new feature built and merged to main, which is the ability to copy the displayed item to the pasteboard by pressing c. This is directly inspired by a feature in K9S, which allows you to copy the logs of a running pod to the pasteboard (I use this feature all the time). The package I’m using to access the pasteboard is github.com/golang-design/clipboard, which seems to offer a nice cross-platform approach to doing this.
The copied item is not meant for machine use. It’s exactly what’s displayed in the item viewport and is intended for tracking items that change over time. What I’ve found myself doing, when I need to track such an item, is to manually select it with Terminal and pasting it to an untitled textedit window. I do this again when the item changes until I’m ready to eye the changes manually. It’s not sophisticated, but it tends to work. And although this feature is not a full-blown item comparer, it will make this use case a little easier. Plus, it will copy the entire image, not just the lines displayed when a viewed item is too large for the viewport.
Speaking of which, the other thing I started working on today was on allowing the user to resize the item viewport to take up more of the screen. At the moment, the displayed item viewport takes up the bottom 14 lines of the screen, and is not resizable. Naturally, for large items, this is not large enough, and having the ability to resize this viewport would be a good thing to have.
I’ve been thinking about the best way to handle this, and I’ve decided that an approach similar to how Vim does this — where you need to press a key-chord followed by a number to move the vertical split between two views — would be a little to annoying here. Too much fine grain control for when you just need the viewport bigger. So, I’m opting for a more course-grain approach, where you simply press w and the viewport size will cycle amongst 5 different sizes:
- 14 rows at the bottom of the screen (the default)
- Half the screen
- All but the top 6 rows of the screen, so you can still see a bit of the table view
- The entire screen (i.e. hiding the table view)
- Completely hidden (i.e. the table view takes up the entire screen).
Doing this will not necessarily steal focus from the table view: even if shown the entire screen, you can still go through each item by pressing Up or Down. But you’ll be able to see more of the selected item.
Anyway, that’s the theory. We’ll see how well this works in practice.
Turning Off Shared Command History in Oh My Zsh
TL,DR: add “unsetopt share_history” to your .zshrc file
I’ve been using Oh My Zsh at work for a few months. As far as terminal config managers go, this one works pretty well. But the default configuration does include something which I found quite annoying.
First, a few words on how I use the terminal. I’m in the terminal constantly in my day to day. At the start of the day, I’m creating terminal tabs and running commands to do things like build the project I’m working on, start a testing session, etc. This all starts very ad-hoc, but over time these tabs take on a particular role. I may run make
and git
in the left-most tab, run tests in the tab next to that, have logs tailing in the one after that, etc. As I start and stop commands in each tab, they all build up a different history, which is usually visible in the terminal output itself. Eventually it comes to the point where in order to run a particular tool, I simply need to switch to the particular tab and press ↑ one or two times to get to it.
Installing Oh My Zsh broke this workflow. Out of the box Oh My Zsh enables shared command history across each session, meaning that the commands recalled when pressing ↑ are the last commands executed in any tab. This meant that when going through the history, the recalled command would be different from the ones that I’ve entered in the tab I’m in. In addition to this resulting in pressing ↑ way more times than I used to — sometimes to the point where I gave up and simply typed the command out again — it also meant that the recalled commands differ from the ones I saw in the tab output itself. This was very jarring.
Fortunately, this feature can be turned off simply by adding the following to your .zshrc file.
unsetopt share_history
I did just this and my old workflow was restored.
I don’t know why shared command history was chosen as the default. Am I in the minority using the terminal this way? Maybe. But I know for certain that this group is larger than a single person. In either case, I’m glad that I was able to disable this “feature”.
The last hold-out.

Discovered something cool on the ATP website. If you play old shows while logged in as a member, you actually get those from the members feed instead of the public one. Not sure if I’m the last person to find this out, but chalk me up as someone delighted by this little feature.
I started seeing job ads for “Blockchain Engineer” on LinkedIn recently. I have no interest in such roles. But I was curious, so I clicked into one to see what it actually entails. Now, LinkedIn is emailing me similar web3 roles, thinking that I’m interested.
Serves me right. 🤦
Dad and I have been watching YouTube cab-rides of the NYC subway system recently. Part of the fun is trying to understand the various track configurations and how the system operates. The size of the network never ceases to amaze.
I had the opportunity to meet up with someone I use to work with at the Bureau of Meterology this morning.
I left the Bureau about five years ago, and although I didn’t work with this person on a daily basis, our two teams were reasonably close. One advantage of working in the team that manages the message switching service (MSS) is that you tend to have dealings with many other teams that need to shuffle data around. This person belong to one such team. He dealt with with software related to severe weather, and the alerts produced by them had to be ferried around by out team.
We talked a little about the Bureau. There have been people that have retired or moved on but the team I use to work with is still largely intact. We talked a little about the project that was meant to have replaced the home grown MSS that our team was responsible for. The goal was to replace it with a commercial, off the shelf package sold by a firm that specialises in software for met services. This was meant to have happened roughly a year or two after I left, way back in 2017. But it turns out that this MSS system will not go quietly. Given how tailored it is to the general operations of the Bureau, replacing it proved way too difficult, and it seemed like those that were trying to do so have given up in defeat, at least for the moment. And I get it, nothing lasts for ever, and eventually this MSS system will have to be replaced by something. But even so, it’s good to hear that it’s still around.
And yes, I asked about the admin tool I built. It’s still being used, and indications seem to be that people still like using it.
I was pleased to hear that. Talking about it this morning bought me back to that particular project. I had fond memories working on it. It was fun, and I was proud of what I was able to build. And yet, despite how difficult it was to step away from it, I can’t help think that doing so was the right decision. Staying on that project would not have help me grow professionally. I’ve learnt so much since then, and feel like a much better developer, thanks to moving on and trying different things. Well, it’s good to have the memories.
Adding A Back-Stack To Dynamo-Browse
Spent some more time working on dynamo-browse, this time adding a back-stack. This can be used to go back to the previously viewed table, query or filter by pressing the Backspace key, kind of like how a browser back button works.
This is the first feature that makes use of a workspace, which is a concept that I’ve been thinking about since the start of the project. A workspace is basically a file storing various bits of state that could be recalled in future launches of the tool. A workspace is always created, even if one is not explicitly specified by the user. The workspace filename be set by using the -w
switch on launch, or if one is not specified, then a new workspace filename within the temp directory is generated. The workspace file itself is a Bolt database, which is a very simple, embeddable key/value store that uses B-Trees and memory-mapped data access. I’m actually using StormDB to access this file, since it provides a nice interface for storing and querying Go structs without having to worry about marshalling or unmarshalling.
The back-stack consist of view-snapshots, which are essentially records of the currently view table, filter, and query. The view-snapshots are stored as a linked list, and the back-stack simply pushes new snapshots as the view changes (because this is stored on file, the backlinks are actually ID references and not physical pointers). I had a bit of trouble getting this right at first. The initial version actually pushed a snapshot of the previous view before it changed (i.e. a new table was selected or the filter was changed). But this resulted in a bit of messy implementation, with push calls copied and pasted across the various controllers with various special cases, etc.
So I went back and reimplemented it so that the top of the back-stack is actually a snapshot of the current view. Pressing the Backspace key will actually pop the current snapshot, then read the head of the stack and use that to update the view. This means that there will always be one item in the stack, which bothered me a little at first, but that did make the code easier to implement.
There is another benefit to this arrangement which just came to me while I was writing this. Since the current state of the view is always at the top of the stack, I could add the ability to restore the last view when launching dynamo-browse with an existing workspace, saving the user from selecting a table and running their last query. This will come a bit later. For the meantime, I need to get this back-stack working with user scripts, so that when a script changes the view, the user can still go back.
Finally, a shoutout to boltcli which is a useful CLI tool for browsing a Bolt database. This tool has come in handy for debugging this feature.
Facinating website for the casual Melbourne train buff. A lot of great photos of rail infrastructure, plus what appears to be routine “photos from 10 years ago” posts, which brings me back. Link via my dad.
The electrification of large vehicles is continuing. For the first time, I just saw and not heard an EV bus. Must say that seeing a bus accelerate out of a roundabout without hearing a loud diesel engine was a unique experience.
It’s funny seeing marking images of devices intended for “work”. There’s always one shot featuring either a graph or a spreadsheet.
Just had an hour long Slack call with someone who was drafting a huge list of tasks in a single Slack message. Thank goodness Slack didn’t fall over, or we would have lost an hour of work. Talk about living on the edge.
MacOS’s virtualisation framework looks interesting and I’d like to get my hands on it. Problem is that I have an Intel mac and it only works on Apple silicon. Now I’m wondering if I’m interested enough to actually open my wallet for it.
More On Scripting In Dynamo-Browse
Making some more progress on the adding scripting of dynamo-browse. It helps being motivated to be able to write some scripts for myself, just to be able to make my own working life easier. So far the following things can be done within user scripts:
- Define new commands
- Display messages to, and get input from, the user
- Read the attributes of, and set the attributes of, the currently selected row (only string attributes at this stage)
- Run queries and get result sets, which can optionally be displayed to the user
Here’s a modified example of a script I’ve been working on that does most of what is listed above:
const db = require("audax:dynamo-browse");
db.session.registerCommand("cust", () => {
db.ui.prompt("Enter user ID: ").then((userId) => {
return db.session.query(`userId="${userId}"`);
}).then((resultSet) => {
db.session.currentResultSet = resultSet;
});
});
db.session.registerCommand("sub", () => {
let currentItem = db.session.selectedRow;
let currentUserId = currentItem.item["userId"];
if (!currentUserId) {
db.ui.print("No 'userId' on current record");
return;
}
db.session.query(`pk="ID#${currentUserId}"`, {
table: "billing-subscriptions"
}).then((rs) => {
db.session.currentResultSet = rs;
});
});
The process of loading this script is pretty basic at the moment. I’ve added a loadscript
command, which reads and executes a particular JavaScript file taken as an argument. Scripts can be loaded on startup by putting these loadscript
commands (along with any other commands) in a simple RC file that is read on launch.
I’m not sure how much I like this approach. I would like to put some structure around how these scripts are written and loaded, so that they’re not just running atop of one another. However, I don’t want too much structure in place either. To me, having the floor for getting a script written and executed too high is a little demotivating, and sort of goes against the ability to automate these one-off tasks you sometimes come across. That’s the downsides I see with IDEs like GoLand and, to a lesser degree, VS Code: they may have vibrant plugin ecosystems, but the minimum amount of effort to automate something is quite high, that it may not be worth the hassle.
A nice middleground I’m considering is to make it to have two levels of automation: one using JavaScript, and the other closer to something like Bash or TCL. The JavaScript would be akin to plugins, and would have a rich enough API and runtime to support a large number of sophisticated use-cases, with the cost being a fair degree of effort to get something usable. The Bash or TCL level would have a lower level of sophistication, but it would be quicker to do these one-off tasks that you can bang out and throw away. This would mean splitting the effort between the scripting API and command line language, which would fall on me to do, so I’m not sure if I’d go ahead with this (the command line “language” is little more than a glorified whitespace split at the moment).
In the meantime, I’ll focus on making sure the JavaScript environment is good enough to use. This will take some time and dog-fooding so they’ll be plenty to do.
I’ve also started sharing the tool with those that I work with, which is exciting. I’ve yet to get any feedback from them yet, but they did seem quite interested when they saw me using it. I said this before, but I’ll say it again: I’m just glad that I put a bit of polish into the first release and got the website up with a link I can share with them. I guess this is something to remember for next time: what you’re working on doesn’t need to be complete, but it helps that it’s in a state that is easy enough to share with others.
Currently enjoying the sound of an eastern rosella singing it’s heart out, helping to make a long tiring week just that little bit easier to deal with.
It wasn’t that long ago where a Google search would return useful results that were not found by either Ecosia or DuckDuckGo. That’s really not happening as often nowadays. In fact, if Ecosia/DDG cannot find anything, there’s very little reason to bother trying Google at all.
Trying to find which countries require 3D Secure for online payments is annoying. Each website only list two or three countries as examples: “3DS is required in some countries like X and Y…”, and do not link to any sources. I need to do like a set union to get the full list.
For the past several weeks, these two have been foraging in front of my place. They’re quite skittish, and will fly off when anyone approaches (it’s difficult to get a picture of them). But after a while, they’ll always return to the same spot.
