fogbound.net




Tue, 12 May 2020

Remembering things for my future forgetful self: developer’s edition

— SjG @ 3:57 pm

I need to record a bunch of training tutorials for a web site. I want to use consistent, fake data, so I set up a local copy of the site. I dumped out the database, and created my test data. As the site evolves, I can continue to check out revisions and run migrations, but still have my customized test data.

So far, so good. But a problem arises. When recording, the URL for my demo site shows up. This will confuse the customer. There’s an easy fix for this, of course, which is to change my demo site to respond to the true site’s hostname, and map it in my /etc/hosts file.

It works great! Except that I’m forgetful. I’ll be adding a new feature on my dev machine, get it approved on the staging server, and eventually check it out of revision control to launch it to the live server. I’ll check, and get confused. Where are my changes? I may go so far as to start looking at the filesystem of the live server and issuing informational commands in the revision control system, which will only confuse me more, as the changes are live. Eventually, I’ll notice that some of the data is demo-like data, and then I’ll kick myself for having wasted half an hour on something so stupid. I’ll comment out the line in my /etc/hosts, and everything will be back to normal… until it comes time to record new tutorials.

It’s time to remind future me. First step is in the terminal. I added the following to my .zshrc file:

export inhost=`egrep '127\.0\.0\.1\s+domain.com' /etc/hosts | wc -l`
export commented=`egrep '#127\.0\.0\.1\s+domain.com' /etc/hosts | wc -l`
if [[ "$inhost" -eq 1 && "$commented" -eq 0 ]]
then
    echo " ____  _______        ___    ____  _____ _"
    echo "| __ )| ____\ \      / / \  |  _ \| ____| |"
    echo "|  _ \|  _|  \ \ /\ / / _ \ | |_) |  _| | | "
    echo "| |_) | |___  \ V  V / ___ \|  _ <| |___|_|"
    echo "|____/|_____|  \_/\_/_/   \_\_| \_\_____(_)"
    echo ""
    echo "-----------------------------------------"
    echo "domain.com is remapped in /etc/hosts!!! "
    echo "-----------------------------------------"
fi

This works well. When I’ve edited the /etc/hosts, my terminal comes up like:

Terminal with warning

But, future me may not go directly to the terminal to diagnose the issue. Future me may foolishly try to compare the current state of the site to the dev or staging version. Never fear! I can save future me from this idiocy.

First, I set my standard test browser to open up new windows and tabs with a “home page” instead of a blank page. That “home page” is http://localhost. I set up the default virtual host, and create an index page with the following barebones code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Home</title>
</head>
<body>
<?php
$server = dns_get_record('domain.com');
if ($server[0]['ip'] == '127.0.0.1')
{ ?>
  <h1 style="color:red">WARNING!</h1>
  <pre style="color:red">
-----------------------------------------
domain.com is remapped in /etc/hosts!!!
-----------------------------------------
  </pre>
  <?php } else { ?> we good.<?php } ?>
  <h2>Search:</h2>
  <form class="search-form-home__form" action="https://startpage.com/sp/search" id="search" method="post">
    <div>
       <input id="q" maxlength="2048" name="query" type="text" value=""/>
       <input type="hidden" name="cat" value="web"/>
       <input type="submit"/>
    </div>
  </form>
</body>
</html>

Now when future me opens up a new browser tab or window, he’ll be greeted with a nearly blank page with a search box. Or possibly a warning!

Warning in browser!

So, by spending a bunch of time now, I can save future me a bunch of time (and frustration). It’s not clear that it will be worth it, but it was definitely worth trying.


Tue, 7 Apr 2020

One-liner to get a directory’s worth of video times

— SjG @ 10:58 am

The ffmpeg family of programs is incredibly arcane and powerful for handling video and video information. I needed to get the run times of a collection of videos. Here’s a handy one-liner that creates output suitable for import into a spreadsheet:

for i in *.mp4; do q=ffprobe -i "$i" -show_entries format=duration -v quiet -of csv="p=0";echo "$i, $q"; done

Sample run:
$ cd ~/work/training_videos
$ for i in *.mp4; do q=ffprobe -i "$i" -show_entries format=duration -v quiet -of csv="p=0";echo "$i, $q"; done
First_steps.mp4, 70.868000
Create_a_project.mp4, 134.320000
Loading_libraries.mp4, 45.442000
...


Fri, 27 Mar 2020

Fixing obsolete Karma test framework

— SjG @ 3:20 pm

Somewhere along the line, I did some software update on my MacBook machine that broke the Karma tests for an AngularJS 1.x application. I don’t know when this happened. I haven’t done work on this project on any computer except on my work desktop in a long, long time.

However, with Covid-19 and the work-from-home regimen, I need to make this work on the MacBook.

When I’d run the tests, I’d get a lovely crash:

27 03 2020 14:35:38.395:ERROR [reporter]: Can not load reporter "junit", it is not registered!
   Perhaps you are missing some plugin?
 27 03 2020 14:35:38.473:INFO [karma]: Karma v2.0.5 server started at http://0.0.0.0:9876/
 27 03 2020 14:35:38.474:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
 27 03 2020 14:35:38.475:ERROR [karma]: { inspect: [Function: inspect] }

Naturally, the first thing I’d do is make sure I’d installed the correct plugin: npm install karma-junit-reporter --save … Node happily reinstalled the plugin, and nothing changed. The source of the issue turned out to be a conflict between the project-installed karma-cli and bits and bobs of an old global install.

I had to clean up the globally-installed stuff that was lurking in /usr/local/bin and /usr/local/lib/node_modules (which is to say, deleted /usr/local/lib/node_modules/karma, /usr/local/lib/node_modules/karma-jasmine, and /usr/local/lib/node_modules/jasmine) leaving everything in the local project install with the exception of karma-cli, which is still globally installed.


Mon, 16 Dec 2019

Maccabeam™ Part 6: Final Project Gallery

— SjG @ 9:38 pm

Previously:
Introduction
Part 1: Simulating candle-light with pseudo-random sequences
Part 2: Some physical structure
Part 3: When Exactly is Hanukkah?
Part 4: A Typical Programming Problem
Part 5: Oil and Lasers

So here we are, six days away from Hanukkah, and the first build of the Maccabeam™ is complete!

Below is video of it running, and a general build gallery. But before that, here are some thoughts and lessons that will go into Version 2 (and/or a kit, if that ever happens).

I build things the old-fashioned way. Everything’s soldered onto a breadboard with finicky little wires (I used wire-wrap wire, since it’s fine and easy to twist around). While this is fine for prototyping, it’s not great for a finished product. I need to learn to use a design app, and have printed circuit boards made.

A printed circuit board would make the positioning of the LEDs better, too. I bought the LEDs on a long strip, which I then cut and wired together. If I used surface-mount LEDs, I wouldn’t have to worry about the width of the strip and making each little segment fit in the channel. It sounds simple, but in the corner areas, it got congested.

The next design won’t just use a printed circuit board. It will also use standard connectors so the disparate parts may be added and removed easily while building.

Back to the LEDs. The decision to put the LEDs behind a layer of frosted acrylic to make the light more diffuse may not have been the right one either. When the “marching ants” animation is running to indicate the shamos lighting the other candles, the diffuse light bleeds over into the neighboring star-shaped windows, disrupting the flow of the animation a little.

The physical hanukkiah, all the laser-cut wood, works well, but it makes access to the internal components very difficult. The screws hold it together, but there’s enough play in the screw-holes that I supplemented with hot glue. When I had to replace one of the laser diodes that burned out, I had to tear the whole thing down. The next design should be more maintainable.

Speaking of lasers, the inexpensive laser diodes I purchased online are not really very good. The brightness varies dramatically! Now, they’re representing candles, so the variation is not a show-stopper, but the dimmer lasers are not bright enough for a well-lit room. You can see this in the video below.

I didn’t write about how I programmed the “music.” To make a long story short, I found sheet music of “Hanukkah Oh Hanukkah” online. Using the Wikipedia article on reading music, I translated the sheet music into the notes. The LCD display has a small piezo-electric speaker on it, and you can play notes by sending special codes on the serial lines to the display. So I took the notes, and translated them into those codes. It’s what the kids call chip-tunes, but perhaps next time I’ll go for the Teensy audio board, and play a stereophonic MP3 off of a memory card.

Another thing I didn’t write about was simulation mode. When the silver switch on the left is thrown to the left, the circuit gets time and date from the GPS unit. But I couldn’t wait for Hanukkah to test my code! Given the number of bugs found and fixed during development, it would have taken me several centuries worth of Hanukkahs to get it right. Therefore, I implemented a simulation mode. When the switch is to the right, we magically locate ourselves in Jerusalem, and set the time just before sundown on the 24th of Kislev. This allowed me to endlessly watch Hannukah arrive, and get the animated displays to my satisfaction.

Anyway, the results are below! We’ll see if it’s satisfactory in just a few days…

View of the LCD Display (Simulation mode)
Start of Day 6 (Simulation mode)

Mon, 9 Dec 2019

Maccabeam™ Part 4: A Typical Code Problem

— SjG @ 8:43 pm

Previously:
Introduction
Part 1: Simulating candle-light with pseudo-random sequences
Part 2: Some physical structure
Part 3: When Exactly is Hanukkah?

The build is coming together.

One discovery was a sneaky bug in the date conversion code. originally, the code had used standard C library for doing some time manipulations. These functions like mktime are used to convert from a structure containing year, month, day, hour, minute, and second to a single large number of seconds. Similarly, there’s gmtime which does the reverse. One nice thing about these functions is that you can use them for arithmetic, e.g., pass mktime all the regular values but a negative value for the hour, then convert back with gmtime to get the computed time. If you want to do the arithmetic yourself, you have to handle all of the boundaries (e.g., if you’ve rolled back into the past hour … or day … etc.)

Under the hood, mktime is doing something like what was described in the last posting about date conversions: it computes a number of seconds from the epoch given the year, month, day, hour etc. The epoch is an arbitrarily defined date and time standard. In most C / Unix environments, it’s the midnight of 1 January 1970 (e.g., the 0th second of 1970). The gmtime function does the reverse, converting a number of seconds from that epoch into a date and time.

I use this feature when computing sunrise and sunset times. Paul Schylter’s suntime.c returns a number of hours and/or minutes to each event. If the sun has already risen on the day you’re computing, for example, you’ll get a negative hour and or minute for sunrise. If the sunrise has not yet happened, the values are positive. I assembling times by adding those offsets to the current hour and minute, and passing the values to mktime. I didn’t have to worry whether the value was still the same hour or day, because mktime sorts it all out for me.

Somewhere along the line, however, I switched from the standard C library for time to using Paul Stoffregen’s Time Library. I did this because it integrates nicely with the GPS. What I neglected was that in C’s standard library, the components of the time structure are integers but in Paul’s library they are unsigned 8-bit integers.

For simple 8-bit integers, the highest-order bit is used for the sign of the number. In other words, a binary value of 00000011 would represent 3, and 10000011 would represent -3. That way, an 8-bit integer can represent values from -127 to 127. An unsigned 8-bit integer, however, uses the highest-order bit like any other bit, so 00000011 would still represent 3, but 10000011 would represent 131!

All this to say, my trick of passing possibly-negative hours or minutes into the equivalent of mktime was not doing what I had thought! When I thought I was computing the time of sunrise that was 7 hours earlier by passing hour - 7, I was actually computing the time as hour + 135. It turns out that tweaking Paul’s library to supports signed integers was simple.

The moral of this particular story is pay attention when changing C libraries.