πŸ”— The Windows 11 Trash Party

There is no way to turn this news feed off. The best you can do is “manage interests” which kicks you out to msn.com to have you tell it what topics you prefer.

Definitely not trying Windows 11. I hate software that pushes news onto you, unsolicited and with no easy way to turn off! I’ve have my news sources that I read and trust. I don’t want things pushed to me from sources with some commercial agreement that doesn’t have my interests in mind.

I’d argue that Google Reader shutting down was probably one of the best things that could happen to RSS. It might’ve been bad at the time, but it gave way to services like Feedbin that respect open standards and bring new users to the format, like myself. Having a large company like Google suck up all the oxygen in the room can’t have been good for RSS long term.

My Pinboard subscription has expired today. I don’t think I’ll be renewing it. Might be time to look for another way to manage my bookmarks.

I think GitLab wasted their effort building their “queued” MR comment feature, in which comments added to code lines are not seen by the submitter until you click “Finish Review” at the bottom of the page. I’ve never concerned myself with the feeling that I need all my comments sent to the submitter at once.

Oh sure, I’ve written a comment and then deleted it minutes later after going a bit further in the code, and I can see the benefit of this feature catching those. But I’ve trained myself to avoid doing that by simply reading ahead. I try not to raise a comment if there’s a chance that I’ll need to go back and modify/delete it. Saving the effort from catching these before the submitter sees them doesn’t seem like it’s worth the complexity of this feature, especially considering that other code review tools I usually used (which is really only GitHub) doesn’t work like that.

No, what I really want GitLab to do is hide/auto-approve files matching a certain pattern. This would be perfect for ignoring generated code changes. I don’t care if generated code changes. I really don’t. And I hate scrolling past these in MRs I need to review, especially when they take up a significant proportion of the changes. It looks like GitLab has an open issue to address this. It’s a shame that it hasn’t been addressed sooner, before this queued MR comment feature was shipped.

Yes, I’m complaining about this because I’m in a mood and I don’t like reviewing code. I blame the fact that it’s a Monday for that.

Wow, some serious work’s happening on the overhead wires of the train line. Looks like they’re replacing these old stanchions. I guess they’ve reached their end of life. Not sure how long they’ve been in service but they look quite old. Certainly older than me at the very least.

Workers attaching overhead wires to new supports with the old one completely devoid of wires.One of the old supports with wires disconnected and not long for this world.

Building F5 To Run

At the risk of talking about something that I’ve only just started, I’d thought today I write about what I’m working on right now.

I’ve been going through my digital archives this weekend, trying to get it into something more permenant than the portable USB drives it’s currently stored on. Amongst all that stuff is a bunch of QBasic apps and games I wrote way back when I was a kid. Over the years it’s laid dormant but I do like revising them from time to time.

Is it a form of nostalgia? An attempts to live past glories? Maybe? I was pretty proud of them at the time, much like anyone else that’s proud of their early stuff while they’re leaning to code. And I know about the risk of living in the past at the expense of the present. But I also know that if I get rid of them, I’d regret it. I already regret loosing the things from the archive so far, due to bad disks or just missing things while copying them from portable hard-drive to portable hard-drive. I don’t want to loose any more.

So in an act of posterity, I’d figured it’s time to coat them in amber and put them online. So that’s what I’m doing now.

These apps run without issue in DosBox, and hearing about how the Wayback Machine has managed to make a bunch of DOS games playable within the browser, I wondered if I could do something similar. Anything that deals with virtualisation is always going to be a little bit involved. I guess one thing going for these is that they were written for a pretty slow machine and a pretty thin OS that would be trivial for modern hardware to emulate. The apps themselves, even compiled to an EXE file, are not very taxing on the hardware back then either. But I still expected to do a bit of heavy lifting myself.

How wrong I was! After a tiny bit of research β€” and by tiny I mean one Ecosia search β€” I managed to find a JavaScript library called JS-Dos which provides a DosBox emulator that’s runnable from a browser. All I need to do is prepare a bundle on what I want to run (more on that below) and with a bit of JavaScript, I can start a DosBox machine in the browser and mount it to a HTML element. The library does all the work.

How To Use JS-Dos

It’s still early days, but here’s what I learnt about using the library so far.

First, the library comes as a NPM package, or can be loaded from their CDN in the form of a <script> import. I first tried using the NPM package, but I didn’t know the appropriate import statement to use, and the documentation was not forthcoming on this front.

So I went with the CDN approach. I’m using Hugo Pipes to fetch the remote JavaScript file and make a local bundle so I can host it from the site itself. It comes with some CSS which I also need to get (note, I’m using parenthesis instead of curly braces here as I’m not sure how to include two curly braces in a code-block).

(( $jsDosCSS := resources.GetRemote "https://js-dos.com/v7/build/releases/latest/js-dos/js-dos.css" ))
<link rel="stylesheet" href="(( $jsDosCSS.RelPermalink ))">
        
(( $jsDosJS := resources.GetRemote "https://js-dos.com/v7/build/releases/latest/js-dos/js-dos.js" ))
<script src="(( $jsDosJS.RelPermalink ))" defer></script>

I also needed to get an appropriate wdosbox emulator. This comes in the form of a WASM file, plus a small JavaScript file which I assume is some simple bootstrapper. I’ve downloaded these and stored them in the static/emulators directory of my Hugo project. The JSDos library loads them on demand and I needed to set the URL path prefix for these two files so that JSDos knows where to get them:

emulators.pathPrefix = '/emulators/';

Next, I needed to build a bundle. These are the DOS programs that are launched with DosBox. They’re effectively just Zip files holding some metadata, the DOS executable, and any files needed for the program to run. There’s some basic information about how to make them, and there’s even an online tool which will take on a lot of the tedious work. I’ve used it to make a couple of test bundles and it works quite well. I’d like to eventually make my bundles myself but I’ll stick with the tool for the time being, at least until I’ve got a DosBox configuration that I’m happy with. One thing the tool does is give you the ability to define an overlay so that these DOS apps are usable from within a mobile browsers. I’ll see if I can get away from needing these overlays at this stage. I’m not expecting anyone with a mobile app to try these out.

The contents of .jsdos/dosbox.conf for the test bundle `logo-2.jsdos`
[sdl]
autolock=false

fullscreen=false
fulldouble=false
fullresolution=original
windowresolution=original
output=surface
sensitivity=100
waitonerror=true
priority=higher,normal
mapperfile=mapper-jsdos.map
usescancodes=true
vsync=false
[dosbox]
machine=svga_s3

language=
captures=capture
memsize=16
[cpu]
core=auto
cputype=auto
cycles=max

cycleup=10
cycledown=20
[mixer]
nosound=false
rate=44100

blocksize=1024
prebuffer=20

[render]
# frameskip: How many frames DOSBox skips before drawing one.
#    aspect: Do aspect correction, if your output method doesn't support scaling this can slow things down!.
#    scaler: Scaler used to enlarge/enhance low resolution modes.
#              If 'forced' is appended, then the scaler will be used even if the result might not be desired.
#            Possible values: none, normal2x, normal3x, advmame2x, advmame3x, advinterp2x, advinterp3x, hq2x, hq3x, 2xsai, super2xsai, supereagle, tv2x, tv3x, rgb2x, rgb3x, scan2x, scan3x.

frameskip=0
aspect=false
scaler=none

[midi]
#     mpu401: Type of MPU-401 to emulate.
#             Possible values: intelligent, uart, none.
# mididevice: Device that will receive the MIDI data from MPU-401.
#             Possible values: default, win32, alsa, oss, coreaudio, coremidi, none.
# midiconfig: Special configuration options for the device driver. This is usually the id of the device you want to use.
#               See the README/Manual for more details.

mpu401=intelligent
mididevice=default
midiconfig=

[sblaster]
#  sbtype: Type of Soundblaster to emulate. gb is Gameblaster.
#          Possible values: sb1, sb2, sbpro1, sbpro2, sb16, gb, none.
#  sbbase: The IO address of the soundblaster.
#          Possible values: 220, 240, 260, 280, 2a0, 2c0, 2e0, 300.
#     irq: The IRQ number of the soundblaster.
#          Possible values: 7, 5, 3, 9, 10, 11, 12.
#     dma: The DMA number of the soundblaster.
#          Possible values: 1, 5, 0, 3, 6, 7.
#    hdma: The High DMA number of the soundblaster.
#          Possible values: 1, 5, 0, 3, 6, 7.
# sbmixer: Allow the soundblaster mixer to modify the DOSBox mixer.
# oplmode: Type of OPL emulation. On 'auto' the mode is determined by sblaster type. All OPL modes are Adlib-compatible, except for 'cms'.
#          Possible values: auto, cms, opl2, dualopl2, opl3, none.
#  oplemu: Provider for the OPL emulation. compat might provide better quality (see oplrate as well).
#          Possible values: default, compat, fast.
# oplrate: Sample rate of OPL music emulation. Use 49716 for highest quality (set the mixer rate accordingly).
#          Possible values: 44100, 49716, 48000, 32000, 22050, 16000, 11025, 8000.

sbtype=sb16
sbbase=220
irq=7
dma=1
hdma=5
sbmixer=true
oplmode=auto
oplemu=default
oplrate=44100

[gus]
#      gus: Enable the Gravis Ultrasound emulation.
#  gusrate: Sample rate of Ultrasound emulation.
#           Possible values: 44100, 48000, 32000, 22050, 16000, 11025, 8000, 49716.
#  gusbase: The IO base address of the Gravis Ultrasound.
#           Possible values: 240, 220, 260, 280, 2a0, 2c0, 2e0, 300.
#   gusirq: The IRQ number of the Gravis Ultrasound.
#           Possible values: 5, 3, 7, 9, 10, 11, 12.
#   gusdma: The DMA channel of the Gravis Ultrasound.
#           Possible values: 3, 0, 1, 5, 6, 7.
# ultradir: Path to Ultrasound directory. In this directory
#           there should be a MIDI directory that contains
#           the patch files for GUS playback. Patch sets used
#           with Timidity should work fine.

gus=false
gusrate=44100
gusbase=240
gusirq=5
gusdma=3
ultradir=C:\ULTRASND

[speaker]
# pcspeaker: Enable PC-Speaker emulation.
#    pcrate: Sample rate of the PC-Speaker sound generation.
#            Possible values: 44100, 48000, 32000, 22050, 16000, 11025, 8000, 49716.
#     tandy: Enable Tandy Sound System emulation. For 'auto', emulation is present only if machine is set to 'tandy'.
#            Possible values: auto, on, off.
# tandyrate: Sample rate of the Tandy 3-Voice generation.
#            Possible values: 44100, 48000, 32000, 22050, 16000, 11025, 8000, 49716.
#    disney: Enable Disney Sound Source emulation. (Covox Voice Master and Speech Thing compatible).

pcspeaker=true
pcrate=44100
tandy=auto
tandyrate=44100
disney=true

[joystick]
# joysticktype: Type of joystick to emulate: auto (default), none,
#               2axis (supports two joysticks),
#               4axis (supports one joystick, first joystick used),
#               4axis_2 (supports one joystick, second joystick used),
#               fcs (Thrustmaster), ch (CH Flightstick).
#               none disables joystick emulation.
#               auto chooses emulation depending on real joystick(s).
#               (Remember to reset dosbox's mapperfile if you saved it earlier)
#               Possible values: auto, 2axis, 4axis, 4axis_2, fcs, ch, none.
#        timed: enable timed intervals for axis. Experiment with this option, if your joystick drifts (away).
#     autofire: continuously fires as long as you keep the button pressed.
#       swap34: swap the 3rd and the 4th axis. can be useful for certain joysticks.
#   buttonwrap: enable button wrapping at the number of emulated buttons.

joysticktype=auto
timed=true
autofire=false
swap34=false
buttonwrap=false

[serial]
# serial1: set type of device connected to com port.
#          Can be disabled, dummy, modem, nullmodem, directserial.
#          Additional parameters must be in the same line in the form of
#          parameter:value. Parameter for all types is irq (optional).
#          for directserial: realport (required), rxdelay (optional).
#                           (realport:COM1 realport:ttyS0).
#          for modem: listenport (optional).
#          for nullmodem: server, rxdelay, txdelay, telnet, usedtr,
#                         transparent, port, inhsocket (all optional).
#          Example: serial1=modem listenport:5000
#          Possible values: dummy, disabled, modem, nullmodem, directserial.
# serial2: see serial1
#          Possible values: dummy, disabled, modem, nullmodem, directserial.
# serial3: see serial1
#          Possible values: dummy, disabled, modem, nullmodem, directserial.
# serial4: see serial1
#          Possible values: dummy, disabled, modem, nullmodem, directserial.

serial1=dummy
serial2=dummy
serial3=disabled
serial4=disabled

[dos]
#            xms: Enable XMS support.
#            ems: Enable EMS support.
#            umb: Enable UMB support.
# keyboardlayout: Language code of the keyboard layout (or none).

xms=true
ems=true
umb=true
keyboardlayout=auto

[ipx]
# ipx: Enable ipx over UDP/IP emulation.

ipx=true
[autoexec]
echo off
mount c .
c:

type jsdos~1/readme.txt
echo on

LOGO.EXE

I’m keeping the bundles in the static/bundles directory, which sits alongside the emulator WASM file. They’re not huge binaries but I’m still using git lfs to manage them. Best to keep the the Git repository relatively sane.

Finally, it’s just a matter of adding some JavaScript to start DosBox, load the bundle, and mount it onto a HTML element:

Dos(document.querySelector("#element-to-mount")).run("/bundles/bundle-to-load.jsdos");

And that’s pretty much it.

Safari window with a test webpage with JSDos running an editor. The editor has the line 'This is the running Dos program.'
A test webpage with JSDos running Logo 2, which is one of my Basic programs

After a few hours, I’ve managed to get a test version of this working. There are a few things that need working on: the app I’m trying require the Alt key, which is not readily available of Apple keyboards, so I may need to do something about that (JSDos comes with a virtual keyboard with Ctrl and Alt so it’s not a complete show-stopper)1. And I’ll need to get styling and more maintainable JavaScript written for this (I’m using StimulusJS for the JavaScript2). But I’m impressed by how well this works, given the minimal amount of effort from my part. Shoulders of giants and all that.


  1. I’ve since learnt that Alt is bound to the Option key in MacOS. ↩︎

  2. One thing I leant about Hugo is that it’s bundled with ESBuild, meaning that it’s resource pipeline supports NPM packages. My understanding is that this is invokable using the js.Build construct. This is super useful to know. ↩︎

Tending to the archive of all my old projects, documents, music, etc. that have survived the many machine transfers over the years. It wasn’t the original plan for this morning, but I think it’s best I work on this now. Not sure the portable drives they’re currently on will last much longer.

Finally got my Twitter archive and uploaded it to Micro.blog (thanks @manton for the awesome feature). Happy that I’ve got an archive of them now, but if I’m honest, there’s only one tweet that I really want to keep.

I realise now the problem I have with Twitter’s request archive settings pane. It’s prompting for a password when I open the pane, not when I request the archive. I want to make sure that my request is still ongoing and I haven’t missed the “in-app notification” or it hasn’t fallen on the floor due to some queue that was backed up or no longer running or goodness knows whatever else is going on over there.

So visiting this settings pane and seeing this:

The download an archive of your data settings pane in Twitter with the request archive button dulled out with the label requesting archive, indicating a pending request

provides a good indicating that the request is still in progress.

But refreshing the page is showing the password prompt that I complained about yesterday. I completely understand getting the password challenge when I request an archive, but when I want to simply open the settings pane? Is knowing that I’ve got a pending archive request considered sensitive enough to require a password check?

Anyway, once I get the archive, I hope never to open settings again (except to eventually close my account). And just as well. I can’t say that it’s a good looking settings page. Everything looks so dull and samey.

P.S. It’s been over 24 hours, what the heck is going on over there? I have so few tweets it would’ve been quicker for me to type them out by hand.

Made some improvements to my Keyboard Maestro macro which converts selected text from camel case to upper-snake case. Made a small fix to deal with common abbreviations like URL or API, which usually appear in all uppercase. The previous version was treating each letter as the start of a separate word, so that URL would be changed to U_R_L.

Here’s the JavaScript portion of the macro:

'use scrict';

const commonAbbrevs = ['URL', 'API', 'SQS', 'DB'];

(function() {
  let app = Application.currentApplication()
  app.includeStandardAdditions = true;

  let text = app.theClipboard();

  // Capital case the common abbreviations so that they'll be properly cased
  for (let abbrev of commonAbbrevs) {
    let capitalCasedVersion = abbrev[0] + abbrev.substring(1).toLowerCase();
    text = text.replaceAll(abbrev, capitalCasedVersion);
  }

  // Convert to upper snake case
  let newText = text.replaceAll(/\B[A-Z]/g, "_$&").toUpperCase();

  app.setTheClipboardTo(newText);
})(); 

Side-note: when I first heard that the let keyword was going to be coming to JavaScript, I heard others say that they wished let would effectively make a constant, much like how let works in Swift. I don’t hold a strong opinion on this, but I kinda wish that ECMA went through with that, since I see a lot of JavaScript code use const in place of let within a function block.

I must say, I’m not a huge fan of this practice. I mean, I can appreciate why they do it, since it reduces the chances of accidentally overriding a variable value. But being someone use to languages where const is reserved for constants values at the top-level, it doesn’t look aesthetically pleasing to me. I think I’ll keep using my lets.

If Musk wants to save money on SMS OTPs, then he can increase the authentication timeout on Twitter’s setting page. I’ve been challenged for an OTP on average once per hour as I wait for my archive to be ready.

Another option is to fix OTPs via emails. I tried that a few times but I never got one.

πŸ“Ί Sash! - Adelante (Official Video)

No, you stop scouring the web for a music video from your childhood and get back to work! πŸ˜€

Okay, I think I got all my transportation booked for Europe. Three train journeys, and one hire car. Plus all the other transport booked already. Only thing to do is organise my international drivers permit, which I’ll do as soon as I can get access to a working scanner.

Argh! My kingdom for a document scanner that has power, a network connection, a functional UI, and that works without needing some terrible app.

We’re currently one for four on this front: I can turn the scanner on. πŸ˜’

πŸ”— You, Me, and UI

Really enjoying these series of articles from The Verge about UI and UX design. Lots of facinating subjects there.

Oh, I also flunked the logo colour test, getting 1 out of 8. I guess a career of chromatology is out of the question for me. πŸ˜„

πŸ”— Children’s author Paul Jennings reflects on childhood, success and his writing process

I’ve was a huge fan of Paul Jennings work when I was a kid. Everything he wrote that I read (or watched), I enjoyed. It’s been a while, but I’m sure I’d still like it if I read it today.

Lake Burley Griffin, taken on a bike ride from Tuggeranong.

Lake Burley Griffin with a row of gum trees in the background.

It’s a shame that NetNewsWire and Feedbin have lost access to Twitter’s API. But, much like Google shutting down products, it provides a useful opportunity to trim my feeds to those that I’m still interested in. Most have had no recent posts for months now so I hope some of them are still out there.

Caught up with my sister, and her two cockatiels this afternoon. Nice to visit them again.

Ivy, the white cockatiel, sitting on my shoulder, preening.Archie, the yellow cockatiel, sitting on my arm.

Greetings from Violet Town, 2 hours into a 6.5 hour trip to Canberra.

Violet Town main street, looking towards the railway line View from the cafe