Skip to main content


Receiving the WWVB time signal in Portugal (by accident)

For many, many years I've owned a Sharper Image clock that sets itself from the WWVB time signal in Fort Collins, CO. Well, it used to set itself when I lived in the US. For much more than a decade the clock has sat by the bed and I've manually set it. And it dutifully looked for a time signal it never received. But it worked absolutely fine with manual setting. Until last night.  At some point between 0300 UTC and 0600 UTC the clock received the WWVB time signal and set itself to EST with DST enabled. This morning the clock was "off" by five hours based on time in Lisbon. The NIST propagation chart for the night doesn't show the signal hitting Portugal but somehow my trusty little clock picked it up. Although it makes sense that it set itself between those hours as that's the best time to "hear" the signal outside North America. It's about 7,700 km along the great circle route from Fort Collins to Lisbon but the signal made it! Since this is a
Recent posts

Cloudflare's SSL/TLS recommender on

The Plan 28 website is a small, static site that I really ought to move to Cloudflare Pages , but... currently it's running on a server that I rent. Since it uses SSL from Cloudflare I wanted to make sure that both the browser to Cloudflare and the Cloudflare to John's Server connections were encrypted.  So I dropped into the Cloudflare Dashboard to check the settings. Sure enough both connections were encrypted but it wasn't using the most secure option (Full (strict)) that requires a certificate on the server that Cloudflare can validate. That can either be one that Cloudflare issues or from a commercial or free CA. Recently, Cloudflare introduced a service that automatically discovers the highest possible security setting for SSL on a site. So I clicked the button... And let Cloudflare do its thing. Not long after I received an email saying that I could use Full (strict) already. Which was a bit of a surprise because I didn't remember setting up a valid certificate

Moving to Cloudflare Pages

At work there's a cool product for deploying websites that has great integration with GitHub, it's called Cloudflare Pages . I use and pay for a lot of Cloudflare products but hadn't got around to using Pages. The nudge came when an old friend from university who has been managing for 24 years(!) told me she'd like to decommission the server. The actual content on was originally generated by a Perl script that output static HTML. From time to time I'd modify the Perl, run it, and deploy the HTML using FTP. Really old school. Over time I moved to just running everything on the server without the FTP mess. And, in reality, most of the content on is on this blog, and that uses Blogger. So I decided to try Cloudflare Pages for the home page and go for the simplest possible page. It's all text and a single page and it looks like this: It's a single HTML file containing a small amount of CSS for the colours and a small amount of JavaScrip

Aeronear: an ambient device showing nearby aircraft

Here in Lisbon it's common to see aircraft because the main airport is in the city rather than being on the outskirts. And for a long time I used FlightRadar24 to answer the question "where did that aircraft come from or where is it going to?" But I really like ambient devices such as my Totoro that gives the weather forecast or bus that shows when the next bus arrives . So, it was time to use a few things I had lying around and make a desktop ambient aircraft monitor that looks like this: This uses a  Raspberry Pi Model 3 ,  PiTFT 3.5" touch screen  (which is kind of wasted because I don't use the touch functionality), a  24 LED NeoPixel ring ,  28BYJ-48 stepper motor , and the ULN2003 driver, and a small model aircraft. It's all contained in an acrylic pot that I got from Muji. The screen shows flight information and model aircraft and LED show the current direction the aircraft is flying (the track) and where to look for the aircraft. The first time the

Dividing n elements into groups of at least size g minimizing the size of each group

At work there's a little project to break up groups of employees into random groups (size 4) and set up Zoom calls between them. We're doing this to replace the serendipitous meetings that sometimes occur around coffee machines, in lunch lines or while waiting for the printer. And also, we just want people to get to know each other. Which lead to me writing some code. The core of which is 'divide n elements into groups of at least size g minimizing the size of each group'. So, suppose an office has 15 employees in it then it would be divided into three groups of sizes 5, 5, 5; if an office had 16 employees it would be 4, 4, 4, 4; if it had 17 employees it would be 4, 4, 4, 5 and so on. I initially wrote the following code (in Python):     groups = [g] * (n//g)     for e in range(0, n % g):         groups[e % len(groups)] += 1 The first line creates n//g  ( // is integer division) entries of size g (for example, if g == 4 and n == 17 then groups == [4, 4, 4, 4] ). Th

All the symmetrical watch faces (and code to generate them)

If you ever look at pictures of clocks and watches in advertising they are set to roughly 10:10 which is meant to be the most attractive (smiling!) position for the hands . They are actually set to 10:09.14 if the hands are truly symmetrical. CC BY 2.0 image by Shinji I wanted to know what all the possible symmetrical watch faces are and so I wrote some code using Processing. Here's the output (there's one watch face missing, 00:00 or 12:00, because it's very boring): The key to writing this is to figure out the relationship between the hour and minute hands when the watch face is symmetrical. In an hour the minute hand moves through 360° and the hour hand moves through 30° (12 hours are shown on the watch face and 360/12 = 30). The core loop inside the program is this:   for (int h = 0; h <= 12; h++) {     float m = (360-30*float(h))*2/13;     int s = round(60*(m-floor(m)));     int col = h%6;     int row = floor(h/6);     draw_clock((r+f)*(2*col+1), (r+f)*(row*2+1),

The difference between parentheses and curly braces in GNU Make

One of the problems/perks of having written a book about GNU Make is that people ping me with questions. This morning someone said to me: " Especially curly braces vs parentheses is something that always confuses me ". As always the first port of call with GNU Make questions should be the FSF's manual . It says the following: " To substitute a variable’s value, write a dollar sign followed by the name of the variable in parentheses or braces: either $(foo)  or ${foo}  is a valid reference to the variable foo . " And that seems to work well: $ cat Makefile foo := $(info $(foo)) $(info ${foo}) $(info $(foo:world=everyone)) $(info ${foo:world=everyone}) $(info $(foo:hello.%=good morning.%)) $(info ${foo:hello.%=good morning.%}) $ make hello.everyone hello.everyone good good make: *** No targets.  Stop. You can see that simple variable references work, as do substitutions (where I changed world to ever