Archive for the ‘Uncategorized’ Category

I've finally joined the 21st century, and gone to serving the site on https. On NearlyFreeSpeech, it should be easy: just run from an SSH terminal. That sets everything up to use Let's Encrypt, but that was failing because I use the Apache httpd RewriteEngine to host, with that domain redirecting to a subdirectory in the directory tree. But Let's Encrypt wants to have access to the .well-known directory in the main directory. So was failing, and messing everything up.

The answer was at (which unfortunately is only visible to NFS members): make sure Apache didn't rewrite the .well-known directory:

RewriteCond %{REQUEST_URI} !\.well-known
RewriteCond %{HTTP_HOST} ^kavanot
RewriteRule // etc.

(meaning if the URI does not contain ".well-known" and the domain starts with kavanot, then do the rewrite.

And now running works! has been great, but their security settings make it hard to update WordPress automatically. I just discovered that WP now has a command line interface that works fine over SSH.

  wp core update
  wp core update-dp

And done!. You can do wp db export to back up the database first.
And updating plugins (for those that can auto-update) is just wp plugin update-all.

My biggest complaint with WP 5.5 is the new post editor. It's a new, simpler editor but all my custom buttons are gone. I suppose I'll have to figure out how to restore the old editor.

The way browser history is implemented, with the History interface, is useful for other things than site navigation. The same idea, basically an extended stack that allows going back and forward, is the same algorithm used for undo/redo, and command line history.

It would be nice to be able to do const h = new History() and h.pushState(someData) with arbitrary states, but the browser won't let you construct a new instance of History. It's only accessible from window.history.

So I re-defined History to allow this.

See the details on the github site.

(It's been almost a year since I've posted. My intellectual life is busy with other things)

I use H&R Block software to prepare my taxes and have been generally very happy, but this year it would not update the program after January 1. Using the automatic update downloaded the updater but it silently failed. Manually downloading from then running that would run WinZip to unpack it, then silently fail. The tech support at H&R Block was useless.

Some Google-ing led to this solution:

  1. Run the update installer from the site as though it was going to work
  2. Wait for it to fail
  3. Find the unpacked downloaded installer:
    1. Windows-R key then type %temp% to open the temporary download folder
    2. Find the most recent folder (it will have a GUID-type name, like {deaf-face-1234}. Open it
    3. There should be an msp file like H&R Block Deluxe 2016 Update.msp
  4. Double click that to run it
  5. Run H&R Block

That's all it took! Obviously the unpacking worked correctly, so I don't know why the program wouldn't run the actual installer.

I figured out how to get all the pages from screen-scraping the Amazon wish list. Basically, look for the "Next" button (it's in a <li class=a-last> element). If that element is present, look for the next page.

function getwishlistitems ($listID, $page=1){
	// ignore parsing warnings
	$wishlistdom = new DOMDocument();
	$wishlistxpath = new DOMXPath ($wishlistdom);
	$items = iterator_to_array($wishlistxpath->query("//div[starts-with(@id,'item_')]"));
	if ($wishlistxpath->evaluate("count(//li[@class='a-last'])")) { // this is the "Next->" button
		$items = array_merge($items, $this->getwishlistitems($listID, $filter, $page+1));
	return $items;

Note that this creates a complication: the array of items now includes nodes from different documents, so you can't use one saved DOMXPath. Instead, where the original code has $wishlistxpath->evaluate($xpath, $node), use

(new DOMXPath($node->ownerDocument))->evaluate($xpath, $node);

Hope this helps someone.

It's been almost a year since I last posted. I'm still programming, but it's mostly visible on github, especially my trying to help with jquery/globalize by implementing nongregorian calendars.

I finally solved a bug that was, um, bugging me. In order to test my Julian Day routines, I needed to create a javascript Date at midnight UTC rather than local time. I thought I was clever when I did:

d = new Date();
d.setUTCFullYear( year );
d.setUTCMonth( month );
d.setUTCDate( date );
d.setUTCHours( 0 );
d.setUTCMinutes( 0 );
d.setUTCSeconds( 0 );

And everything worked fine, until last night when I would set month=1 (February) but the month would end up as 2 (March). This had never happened before, and the code hadn't changed.

I finally realized that the date was 2016-01-28 St. Louis time at 2300, or 2016-01-29 UTC. So setting the year to a non-leap year like 2015, then setting the month to 1 with setUTCMonth() meant I was trying to set it to 2015-02-29, which Date helpfully corrected to 2015-03-01, then the date was set correctly. The only way that bug would turn up is if my code was run on the last day of the month and tested with a shorter month.

Turns out there's a much better way to set UTC time:

d = new Date( Date.UTC( year, month, date ) )

And now I am wiser.

I'm sure there must be an easier way to run a program from PowerShell, but I haven't found anything simpler than

& "C:\Program Files (x86)\Notepad++\notepad++.exe"

with the ampersand and the full path. I could add "C:\Program Files (x86)\Notepad++" to $env:PATH, but I'd still have to type notepad++.exe file. I wanted some way to make a shortcut to a program name without having to create a new file, either a .LNK or .BAT file.

Turns out you can do this with PowerShell functions:

function npp { & "C:\Program Files (x86)\Notepad++\notepad++.exe" $args }

lets me run Notepad++ from PowerShell without nearly so much typing. Stuck that in my Profile.ps1 and now I'm happy.
Hope this turns out to be useful to someone.

We love playing Scribblish. It's like the old Telephone game but with pictures, with players alternating writing captions for pictures and drawing pictures for the captions. It's most fun as a non-competitive party game, just reading the cartoons at the end of each round. It's useful as well: we taught it to my daughter's then-boyfriend and said not to take so much time on detailed drawings; they should look like XKCD. And he knew what I was talking about! Obviously a perfect match. They were married the next year.

Unfortunately no one else seemed to share my family's passion, and the game was discontinued. You can't get replacement pads any more. So I printed my own (it's just a bunch of lines on a sheet of paper cut in thirds). And I wanted to leave it here so I could find it again:

Scribblish-style pad

I wanted to run some of my old games (notably Riven) on my shiny new Windows 8.1 machine, but it wouldn't even try to install on a 64-bit operating system. Luckily, Oracle offers VirtualBox to run virtual machines, and Microsoft offers a Windows XP virtual hard drive (.vhd file) through its Windows XP mode for Windows 7. Note that it won't run directly on Windows 8, but you can extract the .vhd file as outlined by lifehacker:

Then use 7-Zip open the EXE file as an archive.

Within that archive, find the sources/xpm file within it, and extract that folder to your hard drive.

Finally, in the extracted xpm file, you'll find a file called VirtualXPVHD. Export it and rename it to VirtualXPVHD.vhd

In VirtualBox, create a new virtual machine running Windows XP, and instead of creating a new virtual hard drive, use the one created above.

This will give you a new virtual machine that will require you register within 30 days, which you can't do (since Windows XP isn't supported anymore). We'll fix that later.

Start up the virtual machine, deal with the craziness of mouse capturing (toggle the right control key to get the mouse back) until you install "Guest Additions":

In the "Devices" menu in the virtual machine's menu bar, select "Insert Guest Additions CD image" then run that installer in the virtual machine. Now the mouse should integrate smoothly.

In the VirtualBox Manager, in the Network tab, unclick "Cable Connected". You don't want this virus-friendly operating system talking to the internet!

To activate Windows XP, you can try the file named KEY in the exe file with the virtual hard drive, but the comments on lifehacker indicate it won't work. I got a new bios from vmlite, and install it as:

path\to\VirtualBoxFolder\VBoxManage.exe setextradata your-vm-name "VBoxInternal/Devices/pcbios/0/Config/BiosRom" "path\to\pcbios.bin"

And it all seems to work. I don't feel guilty about using a pirated operating system license, since I am running Windows 8 legally, and Microsoft won't sell me XP.

Installing CD's is a pain, and Riven wants to keep swapping them, but making them virtual images makes it much easier. Install ISORecorder (the Windows 7 version works with Windows 8) and now the contextual menu (right-click) for CD's includes a "Create Image from CD" option. Save with the iso extension, and VirtualBox will mount them just fine.

Unfortunately, I now do not have any time to play anything.

Now that I have my computer working, I want to get back at my github repositories. I could type my password with every push, but it's easier to use SSH with a key pair. Since I'm using Putty for shell access, I use Puttygen that comes with it. The problem is that Puttygen's format is not the right one for git. There are recommendations online to set $GIT_SSH to use plink with Pageant, which does use Puttygen's format, but I read that github won't support that, so I ended up doing the following:

Create a key pair with Puttygen. In the conversion menu, create a file in openSSH format. Create the file ~/.ssh/config:

	User git
	IdentityFile /path/to/openssh-format-privatekey

At add the public key that you created. Back in Powershell, in the directory with the local repository, do

git remote set-url origin

to use SSH. Now git push origin master will push the local master branch back up to github without needed a password (if you created the private key with a passphrase, you will have to enter that.

In putty, for each host, set Host Name in the Session tab and select the private key (in Puttygen format!) in the Connection->SSH->Auth tab.