Having used Zsh with Oh My Zsh for all my command line needs for some time I was delighted to discover Oh My Zsh’s zsh_stats command which gives a nice summary of the top 20 most frequently used shell commands.

Here’s my top 20 – what’s yours? Or perhaps you have already stopped reading?

 1    2235  20.3998%   g
 2    1388  12.6689%   l
 3    787   7.18328%   npm
 4    747   6.81818%   cd
 5    391   3.56882%   vi
 6    305   2.78386%   t
 7    294   2.68346%   cat
 8    257   2.34575%   sudo
 9    247   2.25447%   which
10    214   1.95327%   git
11    152   1.38737%   ssh
12    143   1.30522%   vagrant
13    137   1.25046%   rm
14    127   1.15918%   man
15    121   1.10442%   node
16    104   0.949252%  todo
17    102   0.930997%  mv
18    93    0.84885%   grep
19    93    0.84885%   docker
20    92    0.839723%  pwd

(g is an alias for git, l is an alias for ls -al and t is an alias for

Silly that cd is number 4 when Oh My Zsh doesn’t even require it…

[UPDATE] cat has recently overtaken t. Stay tuned command stat fans!


Agreeable smiley

After a friend described yesterday’s effort as “…terrifying… like being at a rave with a disintegrating Edvard Munch” I decided to make a more agreeable version

See the Pen Zdog agreeable smiley by Dan Farrow (@squarebracket) on CodePen.


Zdog animation fun

I’ve been having fun trying out David DeSandro‘s ace javascript pseudo-3D animation library Zdog.

<canvas style="display: block; margin: 40px auto;" class="zdog-canvas" width="480" height="480"></canvas>

			// create illo
			const illo = new Zdog.Illustration({
			  // set canvas with selector
			  element: '.zdog-canvas',
			  scale: 2.5,

			const faceGroup = new Zdog.Group({
  				addTo: illo

			// face
			const face = new Zdog.Hemisphere({
			  addTo: faceGroup,
			  diameter: 180,
			  color: '#ee3',
			  fill: true,

         const face2 = new Zdog.Hemisphere({
           addTo: faceGroup,
           diameter: 180,
           scale: { z: -1 },
           color: '#ff5',
           fill: true,

			// left eye
			const eyeLeft = new Zdog.Ellipse({
			  addTo: faceGroup,
			  diameter: 30,
			  translate: { x: 40, y: -10, z: 50 },
			  rotate: { y: -0.5 },
			  scale: { x: 0.65 },
			  color: '#333',
			  fill: true,

			// right eye
			const eyeRight = eyeLeft.copy({
			  translate: { x: -40, y: -10, z: 50 },
			  rotate: { y: 0.5 },

			// mouth
			const mouth = eyeLeft.copy({
			  diameter: 30,
			  // stroke: 10,
			  translate: { y: 40, z: 40 },
			  rotate: { x: -0.5 },
			  scale: { x: 3 },
			  color: '#333',
           // fill: false,

			// update & render
			// illo.updateRenderGraph();

			let i = 0.1,
				y = 0.005;

			function animate() {
			  // rotate illo each frame
			  // illo.rotate.x = Math.sin(i) * 4.5;
			  i += 0.05;
			  illo.rotate.y = Math.sin(i);
			  illo.rotate.z = Math.cos(i) * 0.5;
			  illo.rotate.x = Math.cos(y+=0.005) * 1.2;
			  mouth.scale.y = Math.cos(i);
			  // animate next frame
			  requestAnimationFrame( animate );

			// start animation

I was thinking of those transparent bouncy balls with things inside them.

Also I used CodePen’s prefill embed feature to embed the pen here and it worked a treat!


Fun fact

CERN’s 30th anniversary of the World Wide Web was held on my 48th birthday. The web has been around for my entire adult life, to the day!


How to apply a negative timing offset to Zoom VTT captions

This seems like it must be a fairly common captioning requirement:

My sister works for a charity and ran an online seminar (I refuse to call it a webinar!) using Zoom. She had made captions for the 90 minute event by taking machine generated captions and painstakingly correcting them. She planned to put the video & captions up on the charity’s YouTube channel.

The problem

The first 40 minutes of the video were not useful and she wanted to trim them. This is easy in YouTube Studio but she found that the captions she had uploaded alongside the video didn’t get trimmed, so all the timings were out of sync.

It seems like a real oversight that YouTube Studio doesn’t do this automatically, but it’s in beta so maybe that feature is coming soon. For now I had to help my sister fix the problem she had spent several hours working on with no progress.

She sent me the VTT caption file which is a text file that looks like this:

00:08:53.340 --> 00:08:54.420
Hi, can you hear me.

00:09:17.550 --> 00:09:18.810
Yes, I can hear you.


The solution

I searched DuckDuckGo and found, a free online tool for working with captions. It can apply timing offsets so it seemed like the perfect solution… until I tried to apply a negative offset which it didn’t seem to support.

My workaround was to apply a positive offset of 60 minutes minus our required negative offset, and then fix the hours using find & replace.

The first caption after the video was edited needed to started at about 00:00:10.000 but in the caption list it started at 00:35:55.140, so I offset the captions by 00:24:04.860.

Once the captions were offset I fixed the hours by doing a find & replace with regular expression in Sublime Text. I searched for ^01: using the regex symbol ^ to only match characters at the start of a line. I replaced ^01: with 00:, then replaced ^02: with 01:

After that I also had to replace --> 01 with --> 00, and -->02 with --> 01 I sent it back to my sister and… it worked!

End result

One very happy & relieved sister!


htaccess debugging workflow

Writing complex mod_rewrite redirection rules with .htacess can lead to a downwards spiral of frustration, paranoia and utter bewilderment.

Today I’m working on a particularly tricky scenario so I decided to get more methodical about it.

Here’s a summary of the workflow I’ve been using. I have to remind myself to be deliberately slow and methodical – if I get impatient and rush ahead I’m much more likely to miss something unexpected and end up going in circles.

My setup uses a locally installed Apache server and the Firefox Selenium IDE plugin:

  • Make a new directory in the server root, to keep everything in one place, with an index.php echoing some debugging info:
    File: <?= __FILE__ ?>
    Script name: <?= $_SERVER[ 'SCRIPT_NAME' ] ?>
    Request URI: <?= $_SERVER[ 'REQUEST_URI' ] ?>
    Query string: <?= $_SERVER[ 'QUERY_STRING' ] ?>
    Cookie check: <?= $_COOKIE[ 'myCookie' ] ?>
  • Break the task up into a list of manageable blocks e.g.
    1. Set a cookie
    2. Append flag to URL if cookie is present
    3. If flag present remove it and set query string
  • Make directories named after each block e.g.
    • /set-a-cookie
    • /append-flag-to-url-if-cookie-is-present
    • /if-flag-present-remove-it-and-set-query-string
  • Each directory contains an .htaccess file and index.php
  • Put a comment at the top of each .htaccess identifying the block it addresses e.g. # set-a-cookie. That way when you start copying & pasting you can keep track of what each block does
  • The index file simply pulls in the root index.php:
    <?php require( '../index.php' );
  • Make a new Selenium test suite and begin constructing a test case for the first block. These tests are generally pretty simple: open a URL and check that the location is redirected as expected.
  • Remember to test for multiple scenarios such as requests for:
    • with trailing slashes
    • without trailing slashes
    • with query strings
    • index.php
    • static files
  • Start working on the .htaccess file, running the tests each time you make a change. Once a block is working move to the next one
  • Repeat until done

Work slowly and try not to make too many changes at once. mod_rewrite may seem like voodoo but don’t let it give you the heebie-jeebies!


How to avoid accidentally posting test content on live sites

It’s quite unprofessional, let alone embarrassing, to post some test content on a development site only to discover you’re actually in the wrong tab and you just posted to the live site.

To avoid this I use the Stylish Add-on for Firefox to inject custom CSS into live sites I’m working on.

For example, I have the following rule for

@-moz-document domain("") {
   html {
      border-left: 30px solid red !important; 

The result is that, in my browser, the live site has a hard-to-ignore red border that acts as a clear visual reminder:

Screenshot of website
Caution: Live site!


Since writing this I’m working with four distinct versions of the site: local development, remote development, remote live and remote legacy (backup of the previous version).

I’ve refined my Stylish rules accordingly to add a custom footer for each. The new rule for the live site is:

@namespace url(;

@-moz-document domain("") {
  body::after {
    z-index: 99999;
    line-height: 40px;
    text-align: center;
    width: 100%;
    font-size: 16px;
    color: #fff;
    background: #800;
    content: "live";
    left: 0;
    position: fixed;
    bottom: 0;

which looks like this:


Whereas the local development version looks like this:

Red = Caution, Green = Go!




Firefox Metabookmarks 3

More progress this week: Metabookmarks is now on github!

I’ve sidelined the custom protocol for now and I’m planning to use a chrome:// content link instead, specified in the chrome.manifest file. This allows arbitrary content files to be bundled inside the plugin file and accessed via chrome:// URLs, and hopefully will get me well on the way.

Using cfx means the content directory and the chrome.manifest files have to be manually added to the plugin.xpi archive. This gets tedious quickly so I wrote a build script to automate the process.

The build script also uses the excellent Extension Auto-Installer add-on to ‘push’ the update to Firefox immediately.

So, my pencils are nice & sharp, the desk is tidy and I’m ready to start some serious hacking!


Firefox Metabookmarks 2

So far so good. The Firefox add-on SDK is really straightforward and I’ve tried a couple of simple examples.

I want to be able to write URLs in the form bookmark:tag which will open a page showing a list of bookmarks matching tag. I need to let Firefox recognise a new bookmark: protocol.

This Stack Overflow post seems like a good starting point.


Firefox Metabookmarks

I’m planning to build a Firefox extension to display a page of bookmarks for a particular tag on a single, bookmarkable page (hence Metabookmarks)

For example: bookmarks://project_javascript would display a page of nicely presented links that have been tagged with project_javascript

I’ve never attempted to build a Firefox extension before so I imagine this could take some time & effort. It’s not as if I don’t have other things going on in my life too…

I’m bookmarking resources with the tag project_metabookmarks, and also here: