Dan Q performed maintenance for GC9GKJA A Fine Pair # 1625 ~ Eynsham

This checkin to GC9GKJA A Fine Pair # 1625 ~ Eynsham reflects a geocaching.com log entry. See more of Dan's cache logs.

I like to check in on my new caches after about a week in the field to ensure there are no teething troubles with their hiding place/weatherproofing etc. All looks good here!

Making an RSS feed of YOURLS shortlinks

As you might know if you were paying close attention in Summer 2019, I run a “URL shortener” for my personal use. You may be familiar with public URL shorteners like TinyURL and Bit.ly: my personal URL shortener is basically the same thing, except that only I am able to make short-links with it. Compared to public ones, this means I’ve got a larger corpus of especially-short (e.g. 2/3 letter) codes available for my personal use. It also means that I’m not dependent on the goodwill of a free siloed service and I can add exactly the features I want to it.

Diagram showing the relationships of the DanQ.me ecosystem. Highlighted is the injection of links into the "S.2" link shortener and the export of these shortened links by RSS into FreshRSS.
Little wonder then that my link shortener sat so close to me on my ecosystem diagram the other year.

For the last nine years my link shortener has been S.2, a tool I threw together in Ruby. It stores URLs in a sequentially-numbered database table and then uses the Base62-encoding of the primary key as the “code” part of the short URL. Aside from the fact that when I create a short link it shows me a QR code to I can easily “push” a page to my phone, it doesn’t really have any “special” features. It replaced S.1, from which it primarily differed by putting the code at the end of the URL rather than as part of the domain name, e.g. s.danq.me/a0 rather than a0.s.danq.me: I made the switch because S.1 made HTTPS a real pain as well as only supporting Base36 (owing to the case-insensitivity of domain names).

But S.2’s gotten a little long in the tooth and as I’ve gotten busier/lazier, I’ve leant into using or adapting open source tools more-often than writing my own from scratch. So this week I switched my URL shortener from S.2 to YOURLS.

Screenshot of YOURLS interface showing Dan Q's list of shortened links. Six are shown of 1,939 total.
YOURLs isn’t the prettiest tool in the world, but then it doesn’t have to be: only I ever see the interface pictured above!

One of the things that attracted to me to YOURLS was that it had a ready-to-go Docker image. I’m not the biggest fan of Docker in general, but I do love the convenience of being able to deploy applications super-quickly to my household NAS. This makes installing and maintaining my personal URL shortener much easier than it used to be (and it was pretty easy before!).

Another thing I liked about YOURLS is that it, like S.2, uses Base62 encoding. This meant that migrating my links from S.2 into YOURLS could be done with a simple cross-database INSERT... SELECT statement:

INSERT INTO yourls.yourls_url(keyword, url, title, `timestamp`, clicks)
  SELECT shortcode, url, title, created_at, 0 FROM danq_short.links

But do you know what’s a bigger deal for my lifestack than my URL shortener? My RSS reader! I’ve written about it a lot, but I use RSS for just about everything and my feed reader is my first, last, and sometimes only point of contact with the Web! I’m so hooked-in to my RSS ecosystem that I’ll use my own middleware to add feeds to sites that don’t have them, or for which I’m not happy with the feed they provide, e.g. stripping sports out of BBC News, subscribing to webcomics that don’t provide such an option (sometimes accidentally hacking into sites on the way), and generating “complete” archives of series’ of posts so I can use my reader to track my progress.

One of S.1/S.2’s features was that it exposed an RSS feed at a secret URL for my reader to ingest. This was great, because it meant I could “push” something to my RSS reader to read or repost to my blog later. YOURLS doesn’t have such a feature, and I couldn’t find anything in the (extensive) list of plugins that would do it for me. I needed to write my own.

Partial list of Dan's RSS feed subscriptions, including Jeremy Keith, Jim Nielson, Natalie Lawhead, Bruce Schneier, Scott O'Hara, "Yahtzee", BBC News, and several podcasts, as well as (highlighted) "Dan's Short Links", which has 5 unread items.
In some ways, subscribing “to yourself” is a strange thing to do. In other ways… shut up, I’ll do what I like.

I could have written a YOURLS plugin. Or I could have written a stack of code in Ruby, PHP, Javascript or some other language to bridge these systems. But as I switched over my shortlink subdomain s.danq.me to its new home at danq.link, another idea came to me. I have direct database access to YOURLS (and the table schema is super simple) and the command-line MariaDB client can output XML… could I simply write an XML Transformation to convert database output directly into a valid RSS feed? Let’s give it a go!

I wrote a script like this and put it in my crontab:

mysql --xml yourls -e                                                                                                                     \
      "SELECT keyword, url, title, DATE_FORMAT(timestamp, '%a, %d %b %Y %T') AS pubdate FROM yourls_url ORDER BY timestamp DESC LIMIT 30" \
    | xsltproc template.xslt -                                                                                                            \
    | xmllint --format -                                                                                                                  \
    > output.rss.xml

The first part of that command connects to the yourls database, sets the output format to XML, and executes an SQL statement to extract the most-recent 30 shortlinks. The DATE_FORMAT function is used to mould the datetime into something approximating the RFC-822 standard for datetimes as required by RSS. The output produced looks something like this:

<?xml version="1.0"?>
<resultset statement="SELECT keyword, url, title, timestamp FROM yourls_url ORDER BY timestamp DESC LIMIT 30" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <row>
        <field name="keyword">VV</field>
        <field name="url">https://webdevbev.co.uk/blog/06-2021/perfect-is-the-enemy-of-good.html</field>
        <field name="title"> Perfect is the enemy of good || Web Dev Bev</field>
        <field name="timestamp">2021-09-26 17:38:32</field>
  </row>
  <row>
        <field name="keyword">VU</field>
        <field name="url">https://webdevlaw.uk/2021/01/30/why-generation-x-will-save-the-web/</field>
        <field name="title">Why Generation X will save the web  Hi, Im Heather Burns</field>
        <field name="timestamp">2021-09-26 17:38:26</field>
  </row>

  <!-- ... etc. ... -->
  
</resultset>

We don’t see this, though. It’s piped directly into the second part of the command, which  uses xsltproc to apply an XSLT to it. I was concerned that my XSLT experience would be super rusty as I haven’t actually written any since working for my former employer SmartData back in around 2005! Back then, my coworker Alex and I spent many hours doing XML backflips to implement a system that converted complex data outputs into PDF files via an XSL-FO intermediary.

I needn’t have worried, though. Firstly: it turns out I remember a lot more than I thought from that project a decade and a half ago! But secondly, this conversion from MySQL/MariaDB XML output to RSS turned out to be pretty painless. Here’s the template.xslt I ended up making:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="resultset">
    <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
      <channel>
        <title>Dan's Short Links</title>
        <description>Links shortened by Dan using danq.link</description>
        <link> [ MY RSS FEED URL ] </link>
        <atom:link href=" [ MY RSS FEED URL ] " rel="self" type="application/rss+xml" />
        <lastBuildDate><xsl:value-of select="row/field[@name='pubdate']" /> UTC</lastBuildDate>
        <pubDate><xsl:value-of select="row/field[@name='pubdate']" /> UTC</pubDate>
        <ttl>1800</ttl>
        <xsl:for-each select="row">
          <item>
            <title><xsl:value-of select="field[@name='title']" /></title>
            <link><xsl:value-of select="field[@name='url']" /></link>
            <guid>https://danq.link/<xsl:value-of select="field[@name='keyword']" /></guid>
            <pubDate><xsl:value-of select="field[@name='pubdate']" /> UTC</pubDate>
          </item>
        </xsl:for-each>
      </channel>
    </rss>
  </xsl:template>
</xsl:stylesheet>

That uses the first (i.e. most-recent) shortlink’s timestamp as the feed’s pubDate, which makes sense: unless you’re going back and modifying links there’s no more-recent changes than the creation date of the most-recent shortlink. Then it loops through the returned rows and creates an <item> for each; simple!

The final step in my command runs the output through xmllint to prettify it. That’s not strictly necessary, but it was useful while debugging and as the whole command takes milliseconds to run once every quarter hour or so I’m not concerned about the overhead. Using these native binaries (plus a little configuration), chained together with pipes, had already resulted in way faster performance (with less code) than if I’d implemented something using a scripting language, and the result is a reasonably elegant “scratch your own itch”-type solution to the only outstanding barrier that was keeping me on S.2.

All that remained for me to do was set up a symlink so that the resulting output.rss.xml was accessible, over the web, to my RSS reader. I hope that next time I’m tempted to write a script to solve a problem like this I’ll remember that sometimes a chain of piped *nix utilities can provide me a slicker, cleaner, and faster solution.

Update: Right as I finished writing this blog post I discovered that somebody had already solved this problem using PHP code added to YOURLS; it’s just not packaged as a plugin so I didn’t see it earlier! Whether or not I use this alternate approach or stick to what I’ve got, the process of implementing this YOURLS-database ➡ XML ➡  XSLTRSS chain was fun and informative.

× × ×

GB number plate sticker no longer valid abroad

This is a repost promoting content originally published elsewhere. See more things Dan's reposted.

GB sticker being affixed to a car.

British motorists driving outside the UK must now remove old-style GB stickers or cover them up.

Instead they should display a UK sticker or have the UK identifier on their number plate.

The UK government guidance has been in place since Tuesday 28 September.

With the replacement of “GB” stickers with “UK” ones, I’ll soon be able to add another joke to my list of jokes that aged badly. I first read this in a joke book when I was a kid:

A young man gets his first car and his younger sister comes to look at it. “What’s this ‘L’ sticker for?” she asks.

“It stands for ‘Learning’,” replies man, “Because I’m still having driving lessons.”

Some time later, after he’s passed his test, the man is preparing to take a trip to France with his friends. His sister points to a sticker on his car. “Does this ‘GB’ mean you’re ‘Getting Better’?”

×

Note #20833

My @FreshRSS installation is the first, last, and sometimes only place I go on the Internet. When a site doesn’t have a feed but I wish it did, I add one using middleware (e.g. danq.me/far-side-rss).

Here’s to the next 20 years of my #RSS addiction.

Dan Q found GC944X7 Pop! Bang! Crack! Goes the Christmas Cracker

This checkin to GC944X7 Pop! Bang! Crack! Goes the Christmas Cracker reflects a geocaching.com log entry. See more of Dan's cache logs.

The second of the caches in this series that I found in between errands, this afternoon, was probably the easiest, because the hiding place reminds me distinctly of one of my own hides! This one, though, enjoys some excellent Christmas theming, for which a FP is due. TFTC!

Dan Q found GC93YF2 O Christmas Tree

This checkin to GC93YF2 O Christmas Tree reflects a geocaching.com log entry. See more of Dan's cache logs.

I’d picked this one out as an essential for this afternoon’s “between jobs” hunt, because it completes my Solar System Wonders set. How pleased I was to find that through this cache a tree is properly – albeit sparsely – decorated. Thanks for this, my third and final cache of the day. I’ll be back to finish the series next time I’m around here with time to spare, I’m sure!

Dan Q found GC93W4C Twelve Days of Caching

This checkin to GC93W4C Twelve Days of Caching reflects a geocaching.com log entry. See more of Dan's cache logs.

Having “solved” all the puzzles some time ago I’m picking away at finding the caches in this series a few at a time, starting the other week, every time I happen to be passing nearby. I felt a little overlooked by nearby windows this drizzly afternoon but I needn’t have engaged my stealth skills: the coordinates were spot on and I soon had the cache in my hand. TFTC.

What’s wrong with what3words?

This is a repost promoting content originally published elsewhere. See more things Dan's reposted.

In his latest video, Andrew provides a highly-accessible and slick explanation of all of the arguments against what3words that I’ve been making for years, plus a couple more besides.

Arguments that he makes that closely parallel my own include that what3words addresses are (a) often semantically-ambiguous, (b) potentially offensive, (c) untranslatable (and their English words, used by non-English speakers, exaggerates problem (a)), and (d) based on an aggressively-guarded proprietary algorithm. We’re of the same mind, there. I’ll absolutely be using this video to concisely explain my stance in future.

Andrew goes on to point out two further faults with the system, which don’t often appear among my arguments against it:

The first is that its lack of a vertical component and of a mechanism for narrowing-down location more-specifically makes it unsuitable for one of its stated purposes of improving addressing in parts of the developing world. While I do agree that what3words is a bad choice for use as this kind of addressing system, my reasoning is different, and I don’t entirely agree with his. I don’t believe that what3words are actually arguing that their system should be used alone to address a letter. Even in those cases where a given 3m × 3m square can be used to point to a single building’s entryway, a single building rarely contains one person! At a minimum, a “what3words”-powered postal address is likely to specify the name of the addressee who’s expected to be found there. It also may require additional data impossible to encode in any standardisable format, and adding a vertical component doesn’t solve this either: e.g. care-of addresses, numbered letterboxes, unconventional floor numbers (e.g. in tunnels or skybridges), door colours, or even maps drawn from memory onto envelopes have been used in addressed mail in some parts of the world and at some times. I’m not sure it’s fair to claim that what3words fails here because every other attempt at a universal system would too.

Similarly, I don’t think it’s necessarily relevant for him to make his observation that geological movements result in impermanence in what3words addresses. Not only is this a limitation of global positioning in general, it’s also a fundamentally unsolvable problem: any addressable “thing” is capable or movement both with and independent of the part of the Earth to which it’s considered attached. If a building is extended in one direction and the other end demolished, or remodelling moves its front door, or a shipwreck is split into two by erosion against the seafloor, or two office buildings become joined by a central new lobby between them, these all result in changes to the positional “address” of that thing! Even systems designed specifically to improve the addressability of these kinds of items fail us: e.g. conventional postal addresses change as streets are renamed, properties renamed or renumbered, or the boundaries of settlements and postcode areas shift. So again: while changes to the world underlying an addressing model are a problem… they’re not a problem unique to what3words, nor one that they claim to solve.

One of what3words’ claimed strengths is that it’s unambiguous because sequential geographic areas do not use sequential words, so ///happy.adults.hand is nowhere near ///happy.adults.face. That kind of feature is theoretically great for rescue operations because it means that you’re likely to spot if I’m giving you a location that’s in completely the wrong country, whereas the difference between 51.385, -1.6745 and 51.335, -1.6745, which could easily result from a transcription error, are an awkward 4 miles away. Unfortunately, as Andrew demonstrates, what3words introduces a different kind of ambiguity instead, so it doesn’t really do a great job of solving the problem.

And sequential or at least localised areas are actually good for some things, such as e.g. addressing mail! If I’ve just delivered mail to 123 East Street and my next stop is 256 East Street then (depending on a variety of factors) I probably know which direction to go in, approximately how far, and possibly even what side of the road it’ll be on!

That’s one of the reasons I’m far more of a fan of the Open Location Code, popularised by Google as Plus Codes. It’s got many great features, including variable resolution (you can give a short code, or just the beginning of a code, to specify a larger area, or increase the length of the code to specify any arbitrary level of two-dimensional precision), sequential locality (similar-looking codes are geographically-closer), and it’s based on an open standard so it’s at lower risk of abuse and exploitation and likely has greater longevity than what3words. That’s probably why it’s in use for addresses in Kolkata, India and rural Utah. Because they don’t use English-language words, Open Location Codes are dramatically more-accessible to people all over the world.

If you want to reduce ambiguity in Open Location Codes (to meet the needs of rescue services, for example), it’d be simple to extend the standard with a check digit. Open Location Codes use a base-20 alphabet selected to reduce written ambiguity (e.g. there’s no letter O nor number 0), so if you really wanted to add this feature you could just use a base-20 modification of the Luhn algorithm (now unencumbered by patents) to add a check digit, after a predetermined character at the end of the code (e.g. a slash). Check digits are a well-established way to ensure that an identifier was correctly received e.g. over a bad telephone connection, which is exactly why we use them for things like credit card numbers already.

Basically: anything but what3words would be great.

Dan Q found GC6H7HD Zoology

This checkin to GC6H7HD Zoology reflects a geocaching.com log entry. See more of Dan's cache logs.

Having succeeded at my primary goal for the evening of finding the challenging sibling of this cache, Herbology, I realised I probably had just enough time left before sunset to find this one, too, if I got a move on. As I ran along the path and rounded the corner to the field at the edge of which this cache is found, though, I was in for a bit of a surprise!

I’ve joked to my partner that the deer in South Leigh seem to be suicidal, based on the frequency with which they will leap out in front of my car or bike on the rare occasions that I pass through the village (I’ve avoided hitting any so far, but they keep trying to make me). Well today it was my turn to narrowly avoid being run over, as a pair of large deer rushed out from the field and almost bowled me over! Perhaps now they’ll understand how startling it is to almost end up ploughing through a living thing and avoid jumping out in front of me? Or perhaps not.

In any case, I quickly found the cache’s hiding place once I’d crossed the field, and I could have probably done it 10 minutes later if I’d needed to… but probably not much beyond that; once the sun was gone my eyes wouldn’t have been up to it! As others have noted, this cache is in need of repair: I’m pretty sure it once must have fit the theme of its siblings but right now it’s a cracked, open shell, miraculously still dry enough inside to sign the log but that’s probably only a matter of time. :-(

Anyway: thanks to the CO for a fun series and a delightful, if frantic, walk some of these Autumn evenings. TFTCaches!

Dan Q found GC6H7JG Herbology

This checkin to GC6H7JG Herbology reflects a geocaching.com log entry. See more of Dan's cache logs.

I get precious little time for geocaching lately: between work, childcare, household and volunteering commitments it’s a challenge to squeeze in a quick expedition here and there. That’s doubly-true as the days get shorter: after finishing work, feeding the children etc. it’s already starting to get dim, and caches that I know will be more-challenging to find – like this D4.5! – become a race against time.

A fortunate side-effect of my unusual living arrangement is that I’m only needed for bathtime and bedtime story-reading duties two nights out of every three, and so when this evening achieved the hat-trick of me not being on bedtime duty, not being urgently needed for work in the evening, and the weather looking good, I leapt onto my bike to come and find this cache. I’d found its sibling Geology a fortnight ago without two much difficulty, but – knowing that Herbology would be much harder! – I’d planned to come out and perform a dedicated search for this and this cache only this evening. I cycled to South Leigh and then up the old Barnard Gate road, stopping at N 51° 46.366, W 001° 25.259′ to lock my bike to a wooden footbridge at the point at which a footpath crosses the road. From there, I jogged North up the path to find the GZ (bringing my front bike light for use as a torch, should the need arise).

I had anticipated that a search would be needed and had a few ideas about the kinds of things I might be looking for, but when after approaching half an hour I’d found nothing at all and had resorted to poking at candidate hiding places with a stick while I shone my torch around, I was worried that this expedition might be a bust. Swallowing my pride, I messaged the CO to see if they might be able to provide a further hint. Amazingly, they were not only online but able to give a hint that pointed me at exactly the kind of thing I ought to be hunting for… because it turned out I’d already moved the cache container while hunting elsewhere in its hiding place!

Upon returning this expertly-stealthy cache to its hiding place, I realised that I might just have time to find the third of this triplet, and so I took off at top speed for Zoology.

Chrome is the new Safari. And so are Edge and Firefox.

This is a repost promoting content originally published elsewhere. See more things Dan's reposted.

I am not saying Apple’s approach is wrong. What Apple is doing is important too, and I applaud the work Apple has been doing in improving privacy on the web.

But it can’t be the only priority. Just imagine what the web would look like if every browser would have taken that approach 20 years ago.

Actually, no, don’t imagine it all. Just think back at Internet Explorer 6; that is what the web looked like 20 years ago.

There can only be one proper solution: Apple needs to open up their App Store to browsers with other rendering engines. Scrap rule 2.5.6 and allow other browsers on iOS and let them genuinely compete.

As a reminder, Safari is the only web browser on iOS. You might have been fooled to think otherwise by the appearance of other browsers in the App Store or perhaps by last year’s update that made it possible at long last to change the default browser, but it’s all an illusion. Beneath the mask, all browsers on iOS are powered by Safari’s WebKit, or else they’re booted from the App Store.

Comic showing Scooby-Doo character Fred removing the mask from the ghosts of different iOS web browsers to find Safari's WebKit beneath all of them.

Neils’ comparison to Internet Explorer 6 is a good one, but as I’ve long pointed out, there’s a big and important difference between Microsoft’s story during the First Browser War and Apple’s today:

  • Microsoft bundled Internet Explorer with Windows, raising the barrier to using a different web browser, which a court ruled as monopolistic and recommended that Microsoft be broken into smaller companies (this recommendation was scaled back on appeal).
  • Apple bundle Safari with iOS and prohibit the use of any other browser’s rendering engine on that platform, preventing the use of a different web browser. Third-party applications have been available for iOS – except, specifically, other browser rendering engines and a handful of other things – for 13 years now, but it still seems unlikely we’ll see an antitrust case anytime soon.

Apple are holding the Web back… and getting away with it.

×

Dan Q found GC6FD6N Cumnor Minions – Norbert

This checkin to GC6FD6N Cumnor Minions - Norbert reflects a geocaching.com log entry. See more of Dan's cache logs.

A quick almost-CnD on the school run. I’d love to come back and do the series someday! Found easily (although the hint object is nowhere in sight!), but container was challenging to open! Luckily the edge of the carabiner I use to clip my GPSr to my belt was up to the task! TFTC.

Dan Q found GC93T66 Mistletoe and Wine

This checkin to GC93T66 Mistletoe and Wine reflects a geocaching.com log entry. See more of Dan's cache logs.

“Solved” all the puzzles some time ago, then came out to find this cache as a drive-by (on the minor, not the major, nearby road, of course!) while in-between other errands nearby. Was looking for something smaller when I laid my hands on the cache container, which I thought looked “out of place”, but the weight balance of the thing I’d picked up felt wrong… like something was loose inside? That’s when I realised I was holding the cache! Signed log and returned it to its spot. TFTC.

Note #19508

When do I #blog? A breakdown of my top four #indieweb content types – articles, reposts, checkins and notes – by month.

Blog posts by type and month, a graph showing how articles barely change throughout the year but reposts are highest in the first half of the year, checkins peak in the spring and summer, and notes get a big boost in November.

Unsurprisingly my checkins, which represent #geocaching/#geohashing activity, grow in the spring and peak in the summer when the weather’s better!

At first I assumed the notes peak in November might have been thrown off by a single conference, e.g. musetech, but it turns out I’ve just done more note-friendly things in Novembers, like Challenge Robin II and my Cape Town meetup, which are enough to throw the numbers off.

×