QZ qz thoughts
a blog from Eli the Bearded

Manual restore of Firefox sessions


Recently I needed to downgrade my Firefox install from 87 to 84 due to a bug. With multiple windows open, I was intermitantly finding some events were being sent to the wrong window. An example is open a new (private) window and start to navigate to a new page, but discover mouse clicks and other events were still being sent to the original window. I started seeing this in FF86 and FF87 did not fix it. By that point the bug was testing my patience, and worse FF87 seemed to have new (unrelated) bugs specifically with one site I use.

So downgrade.

It's been a long time since some Firefox bug has been serious enough to force me to install a different version, particularly a downgrade. So I was surprised to find that Firefox now marks every profile with a browser version and does not let older browsers use profiles from newer ones. Originally when profiles introduced compatibility changes it was somewhat infrequent, and downgrades were usually easy to do.

There are three things I really wanted to preserve:

  1. My open tabs (actual state in the tab, not as critical).
  2. My (few) bookmarks. Of 40 or so bookmarks, about 30 I had created (the others shipped with Firefox), and about half of those I still want.
  3. My preferences.

These have varying degrees of difficulty uncovering from the files in a profile. Session tabs ended up being the most complicated. Working backwards in that list.

Changed preferences are stored one-per-line in prefs.js in the profile directory. The chief complication is the number of entries. Many of them are related to extensions or printing and can just be ignored. Many more are related to internal settings like toolkit.telemetry.* or most of the browser.* ones.

The bookmarks are available in compressed JSON files in the bookmarkbackups profile subdirectory. The compression format is a bit of an oddball. The actual compression type is not so rare, LZ4, but apparently the Mozilla implementation is slightly non-standard. There are a lot of tools out there which can apply the standard LZ4 algorithm to the .jsonlz4 files Firefox makes. I used lz4jsoncat by Andi Kleen. Here ls -rt finds the most recent backup file to operate on.

lz4jsoncat $(ls -rt bookmarkbackups/*.jsonlz4) | jq . | grep '"uri"'

If you are unaware, jq is a JSON Query tool. In the simple usage there, the query is for the whole structure and functions as a JSON pretty printer. Why not use jq to slice and dice the uri entries out? Because they exist in several groups (probably for bookmark folders) and grep was way faster than figuring out the correct jq query to use.

But that brings us to the remaining item of interest for me: the URLs of all my tabs in the session data. There are several files in the sessionstore-backups profile subdirectory. In my inspection they all appeared to be valid sessions from different times, and recovery.jsonlz4 seemed to be the most recent one. No need to resort to time sorted file lists here.

The JSON structure holds a lot of data, from cookies to apparently thumbnail images of the page (base64 encoded for safely storing in JSON). Getting just tab URLs was not easily done with grep, and I needed to work out a jq query. There is a windows[] array with an entry for each window, inside that there is a tabs[] array with a state for each tab, and inside that an entries[] array with the history for each tab. The history is a stack with latest entry first.

lz4jsoncat sessionstore-backups/recovery.jsonlz4 |
    jq -r '.windows[].tabs[].entries[0].url'

For each item ([]) in windows array,
  for each item ([]) in tabs array within it,
    for the first ([0]) item in entries array within it,
      print the url field.
The -r makes the output "raw", which is to say without quotes.

Not as neat and clean as actual session recovery, but a lot better than trying to recover my two dozen tabs from memory.

vi and tags


The vi editor, and the significant vi-clones, as well as Emacs and other editors, support a thing called a "tags file". It's essentially a set of bookmarks or a book's "Index" section fore text files.

The intended use is you run a program that indexes your source code and creates the tag entries for you. For example, with ctags you can run it and have it scan source code in dozens of languages (not just C-like ones, such as Java and Go, but also Postscript, Fortran, and others) and produce a file that tells the editor how to find function and variable declarations. (For Emacs, use the etags program to similar effect.)

The tags functionality is very useful when editing code. I keep tags files in source directories for all of my multi-year projects. You can begin and edit session by running vi -t pickle to open the editor to the file and line that pickle() is defined. Say inside pickle() you find a call to spices() and want to know what it does, position your cursor in the word and hit <ctrl-]>, you jump there. Return to where you were with a :pop. Without the keyword handy to <ctrl-]> upon, you can instead :tag spices as well.

For people using vim as their vi of choice, it might help to know that the entirety of the :help system is built using tags, just slightly tweaked for where to look for the tags file. If you know how to use help in Vim, you know how to use tags. And :help tags can probably teach you something you didn't already know about them.

The tags files are a little more mysterious. Normally people don't create or edit them by hand, but you can or you can create programs to create them for your own special needs.

The basic format, and all I'll cover here, is a text file with three tab separated columns. The first column is the tag name, eg pickle. The second column is the file name, relative to where the tags file is located. The third column is a ex-mode movement within the file. Usually the movement is a search, something like /^int pickle(recipe_t rec)$/ that will unambigously find a single line in the file. But line numbers also work just fine. And search with line number offset works for niche needs, eg /^int pickle(.*)$/+2 to start out on the variable declarations if your syntax looks like the following sample. With :set scrolloff=3 to put some space above the cursor, it may be more useful for you.

#include "brine.h"

int pickle(recipe_t rec)
{
    long     cuke;
    int      salt;
    spices_t spicing = spices(rec);

    /* ... */
}

In traditional vi any command you could put on a : line would work in the movement column, including things like :! rm *. I know Vim has tightened that, and I believe the other vi-clones have as well. If Vim doesn't like any movement in a tags file, it will ignore the whole file.

One trick I have found useful is programmatically generated tags files created with a wrapper program. Rather than have a giant file with all tags, I have a database that I can query and then it generates a tags file (with a single entry) and invokes vim -t main to jump to the exact file and line for me. This can make my query easier to form than remembering a specific tag keyword and does not involve a large flat file with huge redundancy.

Starcrash


I was looking for Caroline Munro works and found this 1978 film. This is a Roger Corman production, and in many ways typical of his stuff: cheap. Considered by some a cult film, it was a quick to market rip-off of Star Wars.

There is an evil overlord with a novelty spaceship. There are a pair of smugglers being pursued by space police. There's risky hyperspace jumps to avoid those space police. There are robots. There's a weapon the size of a planet that needs to be dealt with. There's Akton (played by Marjoe Gortner) a force magic user (it's not really explained, not even to Star Wars: A New Hope level of explanation.)

And there's Stella Star (played by Caroline Munro in costumes not entirely unlike Barbarella). Unlike a lot of Corman's stuff of the era, this is strictly PG, so while Stella is never, eg, topless, she's clearly meant to be the big draw for a teenage male audience. They do spice it up with a planet of "Amazons" who also dress like the weather is rather warm.

The story is amusingly bad, and the special effects are amusing. There are some robots (not all of them) that remind me of Harryhusen's Sinbad films. (Munro became famous as a slave girl in one of those films.)

But Akton. Ugh. He just ruins the film for me. Gortner's rise to fame came from being ordained at age four and preaching on the "revival" circuit for years in his youth, then turning to acting to earn an honest living. It's an interesting story for the actor, but none of that matters for the film. Throughout this he can never seem to not look smug, and it grates. I've seen him in Bobby Jo and the Outlaw and didn't find him as unwatchable there, so I don't think it was Gortner's fault. (To be clear, the reason to watch that film is not him, the outlaw, but Lynda Carter's Bobby Jo.)

One escape pod out of four.

Starcrash at imdb
Star Wars: A New Hope at imdb

Bobby Jo and the Outlaw at imdb

Deja Google News Groups


Those of us who still read Usenet proper have probably all seen instances of 10+ year old threads getting a new post by someone who found it on Deja News or it's Google successor. Eg, last month I saw this reply to a twenty five year-old post.

Newgroups: comp.editors
Date: Fri, 26 Feb 2021 19:21:33 -0800 (PST)
Injection-Info: google-groups.googlegroups.com; [...]
Message-ID: <42d18ee7-712f-41f4-b4af-dba9988b192an@googlegroups.com>
Subject: Re: Maximum line length in Vi
From: Tejasvi S Tomar <tstomar@outlook...>

On Monday, April 17, 1995 at 12:30:00 PM UTC+5:30, Paul Fox wrote:
> G. Ioannou (gi...@cus.cam.ac.uk) wrote:
> : ed
> : Vim
> : Vile
> : They all worked fine with lines over 2000 characters in length, but I
> : don't know the exact limit.
> lines on vile, at least, are limited by the size of an int.
> anyone know what it is in vim?
> paul
> ---------------------------------
> paul fox, p...@foxharp.boston.ma.us (arlington, ma)

It seems there isn't any limit. https://www.oreilly.com/library/view/learning-the-vi/9780596529833/ch15s10.html

Anyway today I encountered a new twist on this. Instead of replying to decade(s) old post through Deja Google, someone instead hunted down my Wikipedia user page and answered a question of mine about Usenet II (dead for at least ten years) on the User Talk page. Really, I had no pressing care about why 4gh was used for the "Distribution" header. I knew it was a reference to some sci-fi book, but didn't really care more than that. And if I did care, the Usenet II page at Wikipedia has had the answer for a while: Usenet II, diff=prev, oldid=181389883

(The same person who added the reference in 2008 is the person who who answered me today on User Talk.)

It makes me wonder if people used to (or maybe still do) get the problem of people writing letters about long ago published stuff after finding it in a library.

C. R. Boffo
123 Main St
Small Town
14 January 1958
Mark Twain
345 Taylor St
San Francisco
Dear Sir,

I am writing to you in regards your piece about the jumping frog trainer that lived in Calaveras County. I don't know if Jim Smiley is training frogs for use in jumping contests, but he should be aware that California law now has mandates about frogs kept for jumping contests. I would also like to say that feeding lead to frogs as that stranger did to Dan'l is just cruel.

Yours sincerely,
C. R. Boffo

Any relation of "C. R. Boffo" to the .a https://en.wikipedia.org/wiki/Colorado_River_toad "bufo "lick for high" toads" is surely coincidental.