&. |

A software developer’s musings on software development

Blank Guitar Tab Generator

Recently, I needed to print some blank guitar tabs. So I thought- I can just create some really simple HTML to generate it. When I started to do this, I had a huge feeling of déjà vu. So I checked my GitHub and, sure enough, I had written a tool for it almost three years ago!

For anyone interested, here is the blank tab generator. You can also view the project on GitHub.

Just... don’t expect a lot. :)


chord-name library published on npm

Hard to believe it has been almost four years since I released Chord-o-matic Chord Constructor. One of the things that surprised me when I began that project was that there wasn’t some standard library or algorithm (that I could find) that simply took an array of notes and returned the name of that chord. So I had to write it myself.

In my free time over the last month or so, I decided to try my hand at building and publishing that algorithm. I extracted the core logic (fortunately I had written it in a way that made it relatively easy to do so), converted to Typescript (sooo much easier to work with than plain JS), and figured out how to publish to npm (alarmingly easy).

So now, the chord-name package is available on npm for the world to use. It will be interesting to see if anyone uses it. I have to suspect that if many people needed this, there would already be something else, but I found some people using my Java BigFraction library which I published on Maven a while back. (I haven’t updated that in a long time but it’s basically feature complete.)

One of the things I’m most proud of is this:

Screenshot of npm package page, with "0 dependencies" circled

I could rant for a while on this topic, and I would hardly be the first to do so. But I will leave that as an exercise for the reader.


Wordle Update!

A follow-up to yesterday’s post about Wordle!

I got some feedback on Facebook1:

Jason: I think your script determines the best starting word for getting the most letters in their correct places (commonly colored green) on the first guess. The odds are pretty low of ever getting them all right. What is likely more valuable is getting the most correct letters regardless of position (commonly colored yellow). This can be used to better inform the second guess which would have a much higher probability of successfully guessing the word. 3-4 yellows is more valuable than 2 greens when a second guess is basically a foregone conclusion.

And I think this is a good point. The algorithm should really favor more common letters, even if they are not in the most likely position, over letters that are in the most likely position but less common. So I’ve made an update to my code that discounts the per-position points to one one-thousandth of their original value. This essentially means that the per-position points only matter when breaking a tie between two words with the same letters, but in different orders (i.e. “RAISE” is a slightly better guess than “ARISE”).

Taking this into account, the best first guess would be one that uses the five most common letters (E S A R O). There was only one word in my list meeting that criteria, AROSE. However, some Googling showed that Wordle also accepts SOARE, an obsolete term for a hawk. When I add this to my word list, I also get it as the most common letter.

So here are the top 40 words with this new algorithm:

   1: soare  42.65
   2: arose  42.64
   3: raise  41.77
   4: arise  41.77
   5: earls  41.68
   6: reals  41.68
   7: laser  41.67
   8: aloes  41.65
   9: tares  41.32
  10: rates  41.32
  11: tears  41.31
  12: stare  41.28
  13: aster  41.28
  14: stoae  41.25
  15: nares  40.77
  16: earns  40.76
  17: saner  40.76
  18: nears  40.75
  19: aisle  40.74
  20: snare  40.74
  21: elisa  40.73
  22: aeons  40.72
  23: eason  40.69
  24: tales  40.30
  25: taels  40.29
  26: teals  40.28
  27: slate  40.27
  28: stale  40.26
  29: least  40.26
  30: tesla  40.25
  31: stela  40.25
  32: steal  40.25
  33: dares  40.12
  34: dears  40.10
  35: reads  40.10
  36: siena  39.83
  37: anise  39.82
  38: lanes  39.75
  39: leans  39.74
  40: elans  39.73

  1. A constructive comment thread on Facebook that didn’t somehow devolve into an argument about guns or abortions! I didn’t know that was still possible! 


What's the Best Word to Start With in Wordle?

Like a lot of people, I’ve been playing Wordle lately. If you’re unfamiliar with Wordle, it’s a website/game where, once per day, you try to guess a five-letter word in six guesses. Kind of a cross between scrabble and hangman. It’s surprisingly addictive.

TL/DR

Perhaps the most important step in Wordle is to have a first word that will probably match something, and I decided to try to algorithmically determine the absolute best starting word.

  • If you don’t want to know what the best word is, read no further.
  • If you want to just know what the word, but don’t care how I determined that, just scroll to the end of this post.
  • If you want to know how I determined the best word, proceed!

What I Built

With that out of the way, let’s get to business. Over the weekend I wrote a little script to determine the best word to use as your first guess. When that was done, I kept fiddling with the script and it kind of evolved into a Text Based Adventure To Solve Wordle.

If you’re interested in running this, you’ll need to be someone who understands Node.js, Git, and NPM. If that’s not you, sorry! If that is you, all you’ve got to do is:

git clone git@github.com:kiprobinson/wordle-solver.git
cd wordle-solver
npm install
npm start

Then just follow the instructions.

How It Works

The algorithm I came up with is:

  1. Start with a list of all five-letter English words.
  2. Look at all of those words, and count how frequently each letter appears in the whole word list, and also how frequently it appears in each individual position.
  3. Go through the whole list and give it a score which is the sum of
    1. The likelihood of each letter appearing in its position (i.e. 1st letter, 2nd letter, etc.)
    2. The likelihood of each unique1 letter appearing anywhere in the word.

So let’s say the word to rate is HELLO. The algorithm gives it a score of:

(freq of H in 1st letter = 3.93) +
(freq of E in 2nd letter = 11.486) +
(freq of L in 3rd letter = 7.157) +
(freq of L in 4th letter = 6.31) +
(freq of O in 5th letter = 2.859) +
(freq of H in any letter = 2.789) +
(freq of E in any letter = 10.486) +
(freq of L in any letter = 5.617) +    <== Note L is only counted once here
(freq of O in any letter = 6.601) -
 = 57.23

So What’s The Best Word Already?!?

Per my algorithm, if it were a word, “SOAES” would be the best starting word2. However, Wordle requires real words as guesses, so here are the top 20 first words, and the scores my algorithm gives them:

 1: tares 122.12
 2: cares 122.02
 3: bares 120.94
 4: sales 120.42
 5: dares 120.18
 6: pares 120.07
 7: tales 120.01
 8: sores 119.12
 9: canes 118.95
10: bales 118.83
11: mares 118.73
12: cores 118.62
13: dales 118.07
14: pales 117.97
15: lanes 117.96
16: banes 117.87
17: fares 117.82
18: lores 117.63
19: sates 117.56
20: bores 117.54

Upon Reflection

A few thoughts I have:

  • My algorithm really likes words ending in “es”. In fact, the first word not ending in “es” is TAELS (two hundred and third best option, and also not a word that I personally was familiar with). However, looking at a list of recent Wordle solutions, none of them are plurals, which would make “es” endings much less likely.
  • The fact SALES is the fourth-best word indicates some kind of a problem. Even though S is really common in first and last letter, and also overall, it would still be a waste of a letter to have a word that repeats a letter. I may tweak the algorithm more- maybe if a word has the same letter twice, it only gets the per-character bonus from the character where it is the most likely. Or I may just leave it because I’ve already spent a lot of time on this.
  • After doing this, I did some Googling to see if anyone else had done what I did. I found a few sites suggesting ADIEU as the first guess because it covers so many vowels. I think (in agreement with my algorithm) that covering R/S/T is still better.

There’s an Update!

I got some feedback after posting this, and made some adjustments. Read the update here.


  1. I say unique because a word that repeats letters is kind of a wasted guess. 

  2. The second-best word is “TOAES”, which actually seems like a better first guess to me because it doesn’t waste a letter on the first S. But the algorithm sees that S in first position gets more points (11.853) than (T in overall (5.246) + T in first letter (6.198)). More on this in “Upon Reflection”. 


2D Printing

Warning: I wrote this blog in 2021. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Over the last couple of weeks I have been making some tweaks to Mini Calendar. In doing so, I decided to try printing it across a few different browsers, and saw that it prints at an inconsistent size. I was a little surprised by this because I use real-world units (centimeters) in my CSS because I’m targeting a 2D-printed artifact on good old-fashioned dead-tree paper.

I did some digging by creating a test page that basically prints a ruler in CSS in four flavors- inline divs that are 1mm wide, inline divs that are 1cm wide, table with cells that are 1mm wide, and table with cells that are 1cm wide. What I found is:

  • Chrome prints correctly except when having very small table cells (i.e. the table with one-millimeter-wide cells). In this case, the cells are printed too wide.
    • Oddly, all the rulers are the same size when rendered on screen, but not when printed.
  • Edge behaves exactly like Chrome. (As I would expect)
  • Safari on Mac seems to consistently print everything defined in centimeters about 6% larger than it should be. So in all versions (table or div) the 15 cm wide ruler is actually just shy of 16 cm when printed
  • Firefox is the only browser I tested that gets everything just right.

I went to a lot of effort analyzing this, and you can see more detailed results along with screenshots on GitHub. I may submit a ticket to Safari and Chrome, which I’m sure they will never address.

For now, my solution for Mini Calendar was to update it to generate the calendar using divs (more specifically, a modern CSS grid) instead of a table. This was long overdue, but also very frustrating. There are things that were obvious to the designers of <table> nearly 30 years ago which are still require ugly hacks to do in modern CSS. The primary example of this is the lack of anything analogous to border-collapse.

It will look pretty much as intended (which is to say, it will just barely fit on a sheet of 8.5x11 paper, and also A4 which is slightly taller) when printed from Chrome or Firefox. But Safari will make it too big and you’ll have to adjust the print settings to get it to fit on one page. Oh well.


Introducing Mini Calendar

Warning: I wrote this blog in 2020. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Every December, for the last decade or so, I open up Excel and meticulously create a specific type of calendar for the coming year. I have a few goals for this calendar:

  1. I need to be able to tape it to the side of my monitor, for quick reference. So it needs to be pretty narrow (about an inch wide).
  2. I don’t want an imaginary gap between months. If Tuesday is the 31st, and Wednesday is the 1st, there’s no reason to show them on different rows of the calendar.
  3. I don’t want to waste space on weekends—this calendar is for work and I don’t work on weekends.
  4. I want to be able to mark my company holidays and PTO days.

Last year, I decided to create an application to generate this. Now you can use it here!

Fair warning: I didn’t really intend for anyone but myself to use this, so it may not be super intuitive. If you have any feedback I’d love to hear it!

Here is a photo of how I use this calendar:

Photo of MiniCalendar example


Stack Overflow reputation

Warning: I wrote this blog in 2019. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Stack Overflow changed leadership recently and seems to be doing that thing where a company knows it has plateaued but doesn’t have any idea what to do about it. It’s not that they’re bad, it’s just that they don’t have much more improvement to make. I’ve noticed that when I google programming questions, I increasingly find the answer on a project’s GitHub page rather than Stack Overflow, which might be the impetus for all these changes. Granted, I don’t follow them very closely any more, so maybe my impression is off.

They brought back the podcast, but it’s pretty boring without Joel Spolsky and they don’t really spend any time talking about Stack Overflow itself. Even when they talk about programming, I just don’t care and I think it’s because everyone agrees with everyone about everything and their opinions are all too safe. They’ve also started blogging like it’s 2009 again—lots of words without saying much.1

But the thing that moved me to write the words you’re currently reading: they’re changing the point value of upvotes on questions, and they are retroactively recalculating everyone’s reputation.

Some background: You may not remember this, or you may be too young to have known, but before Stack Overflow, googling programming questions mostly turned up answers on an awful site called Experts Exchange, which hid the answers behind a paywall. Stack Overflow promised that all answers provided to the site would be under a creative commons license—meaning Stack Overflow did not own them and could not charge for access to them, even if they changed management in the future.

As an early adopter, and a believer in whatever Joel touched, I became pretty active on the site. This meant not just answering questions, but also asking them. I would ask questions even if I figured out the answer, as long I couldn’t find that it was already asked on Stack Overflow, because what the site needed to run Experts Exchange out of business was a lot of questions that Google would think are relevant to people’s searches.

When the site launched, upvotes on questions and answers were both worth 10 points. After a few years, they decided “questions will always come, but good answers are hard to come by”—I’m with you so far—”so we’re going to make upvotes on questions worth only 5 points instead of 10, but leave upvotes on answers at 10 points”—okay that makes sense—”and we’re going to retroactively recalculate everyone’s reputation based on those rules”—wait, what? retroactively??2

At the time, someone did an analysis and posted the users who would lose the most rep due to the recalc, and I’m pretty sure I was the third-most-affected user.3 Sure enough, I lost a ton of my fake internet points. I think it’s one of the main reasons I went from being a heavy user of the site to someone who only goes there when Google sends me there.

So I find it kind of hilarious that they’re now undoing that change—making question upvotes worth 10 points again—and that they are making the change retroactive again. My rep went up by about 30% today, from ~69k to ~91k. I finally get back all my stolen points!!

PS: This is the other reason I stopped being active on Stack Overflow.


  1. Hey, I’m also currently writing a long blog that almost no one will read, but at least I don’t do it three times a week. 

  2. There’s an interesting discussion to be had here about fairness. They said they were going to apply the changes retroactively because it wouldn’t be fair to newer users that they would operate under different rules. I think that it’s unfair to punish the old users for doing the things you wanted them to do at the time. But the truth is, I’m 100% convinced, the reason the rules were applied retroactively is because they didn’t want to have to write logic into the rep-calculation code to make events worth different amounts depending on when they happened. 

  3. If I cared more I would try to dig up that post... but I don’t. 


Javascript Date Expert

Warning: I wrote this blog in 2019. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

My most popular contribution to Stack Overflow, by far, is an answer to the question “How to add 30 minutes to a JavaScript Date object?”. That answer turns ten years old today. It has reached over half a million developers, and earned me over eight thousand fake internet points.

I kind of stopped being active on the site something like 8-9 years ago, though. I mainly use it passively now—I only go there when Google results send me there. I do still maintain my old answers if someone adds a comment saying there is an issue with it, although I usually won’t see those comments until the next time I end up on Stack Overflow and notice a red number in the header.


Sometimes, don't be friendly to the user

Warning: I wrote this blog in 2019. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

I’ve recently come to the revelation that sometimes it’s okay—desirable, even—to go out of your way to make software that is not user-friendly or easy to use. In specific situations.

Consider a nuclear weapons facility with a plastic box1 over the launch button2, or the familiar “in case of emergency break glass” boxes with an axe or fire alarm or something3. What these have in common is that obstacles are put in place between the user and the system they control in order to artificially make certain actions more difficult. Say, the action of butt-dialing a nuclear holocaust.

This is not user-friendly; this is, in fact, making the device more difficult for the user.

A while back, I added something similar to some of my code. One of my responsibilities is to write/maintain some DevOps tools that are used to deploy updates to various servers. Deployments can be pretty difficult, so I made this tool as easy to use as possible. I made it so easy, in fact, that people would accidentally deploy to the wrong server. Like, deploying to a production server in the middle of the day. Uh-oh!

My first fix for this was to make the user type the name of the deployment target that they had just selected. But even this was not enough, because people would blindly type in the name without thinking about it. But, based on a consistent server naming convention, I can tell whether the deployment target is a production server or not. When I detect this happening, I put up yet another dialog in front of the user:

Dialog box: Slow down pardner! It looks like you are deploying to production! If this is really what you meant to do, enter "deploy to production" into the box below.

This serves a purpose similar to the glass over the fire alarm: it forces the user to slow down and consider what they are doing. And because this is an internal tool, I get to have a little more fun with the verbiage. :)


  1. I have always thought these things should have a cool name, but as far as I can tell they don’t have one. 

  2. I’m not sure if this actually exists or if it is just from the movies. My attempts to google it mainly turned up photos of movie props. 

  3. I’ve always thought this is a little strange. Like, “hey we’ve got an emergency here”, “I know what we should do! Let’s put some broken glass on the ground!” 


Introducing Everytime

Warning: I wrote this blog in 2019. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Time zones are hard. Everytime makes them easy!

Everytime sits in your system tray, and it shows the current time in as many time zones as you want. Get it on GitHub

Everytime screencap