<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/rss-style.xsl" type="text/xsl"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	     xmlns:dc="http://purl.org/dc/elements/1.1/"
	   xmlns:atom="http://www.w3.org/2005/Atom"
	     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>Terence Eden’s Blog</title>
	<atom:link href="https://shkspr.mobi/blog/comments/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Tue, 02 Jun 2026 17:59:29 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://shkspr.mobi/blog/wp-content/uploads/2023/07/cropped-avatar-32x32.jpeg</url>
	<title>Terence Eden’s Blog</title>
	<link>https://shkspr.mobi/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title><![CDATA[Using FourSquare's API to post location checkins to social media]]></title>
		<link>https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/</link>
					<comments>https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 02 Jun 2026 11:34:51 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[BlueSky]]></category>
		<category><![CDATA[FourSquare]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[MastodonAPI]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=68230</guid>

					<description><![CDATA[What is this, 2016?  I like sharing my location with my pocket friends sometimes. If I&#039;m in a cool bar that they know, perhaps they can recommend a drink. If they live nearby, maybe they want to come for dinner. Not everyone has FourSquare&#039;s SwarmApp, so it is handy to automatically share its updates with other people.  Of course, Swarm doesn&#039;t cross-post to social media because walled-gardens…]]></description>
										<content:encoded><![CDATA[<p>What is this, 2016?</p>

<p>I like sharing my location with my pocket friends sometimes. If I'm in a cool bar that they know, perhaps they can recommend a drink. If they live nearby, maybe they want to come for dinner. Not everyone has FourSquare's SwarmApp, so it is handy to automatically share its updates with other people.</p>

<p>Of course, Swarm doesn't cross-post to social media because walled-gardens are the most profitable. This is my attempt to open it back up again.</p>

<p>Here's what they look like on BlueSky and Mastodon:</p>

<blockquote class="bluesky-embed" data-bluesky-uri="at://did:plc:i6misxex577k4q6o7gloen4s/app.bsky.feed.post/3mmlb3yva3b2x" data-bluesky-cid="bafyreifyyuioy5zwpghfyqcdx7pjippygsg3o3nr3svtvf7owqsdjlygxy" data-bluesky-embed-color-mode="system"><p lang="en">Checked in to Hamburger Fischmarkt, Große Elbstr. 9 (Fischmarkt), Germany

Probably a *bit* early for a breakfast beer.
See on Swarm<br><br><a href="https://bsky.app/profile/did:plc:i6misxex577k4q6o7gloen4s/post/3mmlb3yva3b2x?ref_src=embed">[image or embed]</a></p>— Terence Eden (<a href="https://bsky.app/profile/did:plc:i6misxex577k4q6o7gloen4s?ref_src=embed">@edent.tel</a>) <a href="https://bsky.app/profile/did:plc:i6misxex577k4q6o7gloen4s/post/3mmlb3yva3b2x?ref_src=embed">24 May 2026 at 07:45</a></blockquote>

<script async="" src="https://embed.bsky.app/static/embed.js" charset="utf-8"></script>

<blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@Edent/116642179645011519/embed" style="background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;"> <a href="https://mastodon.social/@Edent/116642179645011519" target="_blank" style="align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 79 75"><path d="M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z" fill="currentColor"></path></svg> <div style="color: #787588; margin-top: 16px;">Post by @Edent@mastodon.social</div> <div style="font-weight: 500;">View on Mastodon</div> </a> </blockquote>

<script data-allowed-prefixes="https://mastodon.social/" async="" src="https://mastodon.social/embed.js"></script>

<h2 id="tldr"><a href="https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/#tldr">tl;dr</a></h2>

<p>You can <a href="https://gitlab.com/edent/swarmtosocial/-/blob/main/swarmtosocial.py">get the SwarmToSocial code from my GitLab</a>.</p>

<p>At the moment, developers get <a href="https://foursquare.com/pricing/">10,000 API calls for free each month</a>. That's probably more than enough for most personal uses.</p>

<h2 id="documentation"><a href="https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/#documentation">Documentation</a></h2>

<p>I was pleasantly surprised that <a href="https://docs.foursquare.com/developer/reference/create-a-checkin">FourSquare's CheckIn documentation</a> was fairly easy to use and understand.</p>

<p>Once you've <a href="https://foursquare.com/developers/home">signed up for a developer account</a> you can create an OAuth app. That will generate a Client ID (<code>ABC123</code>), Client Secret (<code>XYZ789</code>), and you supply a Project URL.</p>

<p>Once done you can <a href="https://docs.foursquare.com/developer/reference/personalization-apis-authentication">follow the Authentication documentation</a>. Or just visit:</p>

<pre><code class="language-_">https://foursquare.com/oauth2/authenticate?
   client_id=ABC123
  &amp;response_type=code
  &amp;redirect_uri=https://example.com/
</code></pre>

<p>Sign in with your FourSquare account. It will redirect you to:</p>

<p><code>https://example.com/?code=456QWE</code></p>

<p>Use that code to construct the final URl:</p>

<pre><code class="language-_">https://foursquare.com/oauth2/access_token?
   client_id=ABC123
  &amp;client_secret=XYZ789
  &amp;grant_type=authorization_code
  &amp;redirect_uri=http://example.com/
  &amp;code=456QWE
</code></pre>

<p>That will respond with the Access Token:</p>

<pre><code class="language-json">{
   "access_token":"asdfghjkl123456"
}
</code></pre>

<p>Hurrah! Posting a new checkin is <em>relatively</em> simple. POST to this URl with a header of <code>accept: application/json</code></p>

<pre><code class="language-_">https://api.foursquare.com/v2/checkins/add?
   v=20260223
  &amp;venueId=13600425
  &amp;shout=This%20is%20a%20test
  &amp;oauth_token=asdfghjkl123456
</code></pre>

<ul>
<li><code>v</code> is, rather confusingly, a date. <a href="https://docs.foursquare.com/developer/reference/versioning">The versioning documentation</a> has more details but, basically, set it to the date you deployed your app.</li>
<li><code>venuId</code> you'll need to find yourself (more on that later).</li>
<li><code>shout</code> is up to 140 characters (!) of URl encoded text.</li>
</ul>

<p>That will send back rather a lot of JSON. Here are the important bits:</p>

<pre><code class="language-json">{
  "meta": {
    "code": 200,
    "requestId": "123456789"
  },
  "response": {
    "checkin": {
      "id": "987654321",
      "createdAt": 1771843820,
      "type": "checkin",
      "visibility": "closeFriends",
      "shout": "This is a test of the API",
      "timeZoneOffset": -300,
      "editableUntil": 1771930220000,
      "user": {
        "id": "56367",
        "firstName": "Terence",
        "lastName": "Eden",
        "relationship": "self",
        "displayName": "Terence Eden"
      },
      "venue": {
        "id": "QWERTYUIOP",
        "name": "My Birthday Party!",
        "contact": {},
        "location": {
          "isFuzzed": true,
          "lat": 39.123456789,
          "lng": -84.987654321,
          "cc": "US",
          "city": "Cincinnati",
          "state": "KY",
          "country": "United States",
          "formattedAddress": [
            "Cincinnati, KY",
            "United States"
          ]
        }
      },
      "checkinShortUrl": "https://swarmapp.com/user/56367/checkin/987654321?s=wRZ7ByNfCW1DNrOIpsRcytPZelE"
    }
  }
}
</code></pre>

<p>For my purposes, the <code>shout</code> and <code>checkinShortUrl</code> are the most important. You can view a sample check in:</p>

<p><a href="https://swarmapp.com/user/56367/checkin/699c34b55bad6b7fb1695544?s=LA7jCaAtH-s9CwSpgQrQdHrP5-8">https://swarmapp.com/user/56367/checkin/699c34b55bad6b7fb1695544?s=LA7jCaAtH-s9CwSpgQrQdHrP5-8</a></p>

<h2 id="venue-id"><a href="https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/#venue-id">Venue ID</a></h2>

<p>If you're already using <a href="https://shkspr.mobi/blog/2018/11/extracting-your-data-from-untappd/">a service like Untappd</a> you might be able to get the venue ID from that.</p>

<p>If not, FourSquare provides <a href="https://opensource.foursquare.com/os-places/">100 million points of interest</a> for free - although with <a href="https://community.openstreetmap.org/t/foursquare-releases-100m-poi-dataset-under-apache-2-0/121883">questionable data quality</a>.</p>

<p>Alternatively, you can <a href="https://docs.foursquare.com/fsq-developers-places/reference/place-search">search by location</a>:</p>

<pre><code class="language-_">curl --request GET \
     --url 'https://places-api.foursquare.com/places/search?ll=51.123%2C0.123&amp;radius=1000&amp;sort=POPULARITY' \
     --header 'X-Places-Api-Version: 2025-06-17' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer ABC123'
</code></pre>

<p>As far as I can see, the <code>Bearer Token</code> only exists <a href="https://docs.foursquare.com/fsq-developers-places/reference/place-search">on the documentation page</a>. I couldn't find it in my developer console. Weird!</p>

<p>That gets you back:</p>

<pre><code class="language-json">{
  "results": [
    {
      "fsq_place_id": "4be584ed2457a593ad8cab15",
      "latitude": 51.11783041264215,
      "longitude": 0.11219274871133413,
      "categories": [
        {
          "fsq_category_id": "4bf58dd8d48988d1fa941735",
          "name": "Farmers Market",
          "short_name": "Farmers Market",
          "plural_name": "Farmers Markets",
          "icon": {
            "prefix": "https://ss3.4sqi.net/img/categories_v2/shops/food_farmersmarket_",
            "suffix": ".png"
          }
        }
      ],
      "date_created": "2010-05-08",
      "date_refreshed": "2025-11-01",
      "distance": 970,
      "extended_location": {},
      "link": "/places/4be584ed2457a593ad8cab15",
      "location": {
        "address": "",
        "locality": "Hartfield",
        "region": "East Sussex",
        "postcode": "",
        "admin_region": "England",
        "country": "GB",
        "formatted_address": "Hartfield, East Sussex"
      },
      "name": "Perryhill Farm Shop",
      "placemaker_url": "https://foursquare.com/placemakers/review-place/4be584ed2457a593ad8cab15",
      "related_places": {},
      "social_media": {
        "twitter": ""
      },
      "tel": "",
      "website": "http://www.perryhillorchards.co.uk/index.php?sec=4"
    },
    {
      "fsq_place_id": "8896f77565e54a658585301d",
      "latitude": 51.11649,
      "longitude": 0.13131,
      "categories": [],
      "date_created": "2021-12-06",
      "date_refreshed": "2021-12-06",
      "distance": 909,
      "extended_location": {},
      "link": "/places/8896f77565e54a658585301d",
      "location": {
        "address": "Priory Park, Beech Green Lane",
        "locality": "Withyham",
        "region": "East Sussex",
        "postcode": "TN7 4DB",
        "admin_region": "England",
        "post_town": "Hartfield",
        "country": "GB",
        "formatted_address": "Priory Park, Beech Green Lane, Withyham, East Sussex, TN7 4DB"
      },
      "name": "Spectra Studios",
      "placemaker_url": "https://foursquare.com/placemakers/review-place/8896f77565e54a658585301d",
      "related_places": {},
      "social_media": {},
      "tel": "01892 487149"
    },
  ],
  "context": {
    "geo_bounds": {
      "circle": {
        "center": {
          "latitude": 51.123,
          "longitude": 0.1234
        },
        "radius": 1000
      }
    }
  }
}
</code></pre>

<p>You can manually check a place using the Placemaker site: <a href="https://foursquare.com/placemakers/review-place/64eca80f0398c97ab52298ec">https://foursquare.com/placemakers/review-place/64eca80f0398c97ab52298ec</a></p>

<h2 id="getting-existing-checkins"><a href="https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/#getting-existing-checkins">Getting Existing Checkins</a></h2>

<p>What if you've checked in to a place using the official Swarm app? How do you get your own recent checkin data?</p>

<p>Again, there is <a href="https://docs.foursquare.com/developer/reference/get-user-checkins">documentation on getting user checkins</a>.</p>

<pre><code class="language-bash">curl --request GET \
     --url 'https://api.foursquare.com/v2/users/self/checkins?v=20260223&amp;limit=2&amp;offset=0&amp;oauth_token=asdfghjkl123456' \
     --header 'accept: application/json'
</code></pre>

<p>Where it says <code>oauth_token</code> it <em>actually</em> means the <code>access_token</code>.</p>

<p>The JSON that is returned is a bit verbose, so I've simplified it here:</p>

<pre><code class="language-json">{
  "meta": {
    "code": 200,
    "requestId": "699c6505b488565a31e315e3"
  },
  "response": {
    "checkins": {
      "count": 2344,
      "items": [
        {
          "id": "699c34b55bad6b7fb1695544",
          "createdAt": 1771844789,
          "type": "checkin",
          "visibility": "closeFriends",
          "entities": [],
          "shout": "Testing the API using an Untappd FourSquare ID.",
          "timeZoneOffset": 0,
          "editableUntil": 1771931189000,
          "venue": {
            "id": "64eca80f0398c97ab52298ec",
            "name": "Abbey Wood Fossil Pit",
            "contact": {},
            "location": {
              "lat": 51.487514,
              "lng": 0.13048041,
              "postalCode": "SE2 0AX",
              "cc": "GB",
              "country": "United Kingdom",
              "formattedAddress": [
                "SE2 0AX"
              ]
            },
            "createdAt": 1693231119
          },
        },
</code></pre>

<p>Annoyingly, there's no <code>checkinShortUrl</code> which means it can't easily be shared.</p>

<p>For that, you'll need to <a href="https://docs.foursquare.com/developer/reference/get-checkin-details">use the <code>get-checkin-details</code> API</a>:</p>

<pre><code class="language-bash">curl --request GET \
     --url 'https://api.foursquare.com/v2/checkins/699c34b55bad6b7fb1695544?v=20250202&amp;oauth_token=asdfghjkl123456' \
     --header 'accept: application/json'
</code></pre>

<p>Which will return this (truncated for brevity):</p>

<pre><code class="language-json">{
  "meta": {
    "code": 200,
    "requestId": "699c67de5f5c0a0e8ab234db"
  },
  "response": {
    "checkin": {
      "id": "699c34b55bad6b7fb1695544",
      "createdAt": 1771844789,
      "type": "checkin",
      "shout": "Testing the API using an Untappd FourSquare ID.",
      "timeZoneOffset": 0,
      "checkinShortUrl": "https://swarmapp.com/user/56367/checkin/699c34b55bad6b7fb1695544?s=LA7jCaAtH-s9CwSpgQrQdHrP5-8",
</code></pre>

<h2 id="photos"><a href="https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/#photos">Photos</a></h2>

<p>If there's a photo with the checkin, it will be return in the JSON like this:</p>

<pre><code class="language-json">{
  "response": {
    "checkin": {
      "photos": {
        "count": 1,
        "items": [
          {
            "id": "699f3a9f96799c05c0f16c9c",
            "createdAt": 1772042911,
            "prefix": "https://fastly.4sqi.net/img/general/",
            "suffix": "/56367_5VYox4Y-hs66wURVsYc1NLgOokfwBfcWhtKQrOlMdD8.jpg",
            "width": 1008,
            "height": 1344,
</code></pre>

<p>The URl for the image is <code>prefix width x height suffix</code> - in this case <a href="https://fastly.4sqi.net/img/general/1008x1344/56367_5VYox4Y-hs66wURVsYc1NLgOokfwBfcWhtKQrOlMdD8.jpg">https://fastly.4sqi.net/img/general/1008x1344/56367_5VYox4Y-hs66wURVsYc1NLgOokfwBfcWhtKQrOlMdD8.jpg</a></p>

<p>You can adjust the width and height if you want a thumbnail or some other resolution.</p>

<p>If there's no photo, the count will be 0.</p>

<h2 id="putting-it-all-together"><a href="https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/#putting-it-all-together">Putting it all together</a></h2>

<p>Every 15 minutes, <a href="https://gitlab.com/edent/swarmtosocial/-/blob/main/swarmtosocial.py">the SwarmToSocial code</a> does the following:</p>

<ol>
<li>Get the most recent checkin.</li>
<li>Read a local file to get the previously seen checkin ID.</li>
<li>If the checkin ID hasn't been seen before:

<ol>
<li>Get the checkin details.</li>
<li>Get the photo if it exists</li>
<li>Post the checkin (plus photo) to Mastodon &amp; BlueSky.</li>
<li>Save the checkin ID to a file.</li>
</ol></li>
</ol>

<p>Enjoy!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=68230&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/06/using-foursquares-api-to-post-location-checkins-to-social-media/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Who are the actors in the UK's 2015 passport?]]></title>
		<link>https://shkspr.mobi/blog/2026/05/who-are-the-actors-in-the-uks-2015-passport/</link>
					<comments>https://shkspr.mobi/blog/2026/05/who-are-the-actors-in-the-uks-2015-passport/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 31 May 2026 11:34:08 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[FoI]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[sexism]]></category>
		<category><![CDATA[shakespeare]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70568</guid>

					<description><![CDATA[I got nerdsniped by a bloody Reddit post!  In 2015, the UK Government launched a new passport design. It immediately attracted negative press for its designers&#039; &#34;sexist&#34; decision to feature more men than women.  The government has been accused of sexism over the new UK passport design, which commemorates the achievements of two women but seven men.  It&#039;s true that there are only two named women - …]]></description>
										<content:encoded><![CDATA[<p>I got <a href="https://xkcd.com/356/">nerdsniped</a> by a bloody <a href="https://www.reddit.com/r/AskUK/comments/1ssf943/">Reddit post</a>!</p>

<p>In 2015, the UK Government launched <a href="https://www.gov.uk/government/news/new-uk-passport-design-launched">a new passport design</a>. It immediately attracted negative press for its designers' <a href="https://www.bbc.co.uk/news/uk-34710261">"sexist" decision to feature more men than women</a>.</p>

<blockquote><p>The government has been accused of sexism over the new UK passport design, which commemorates the achievements of two women but seven men.</p></blockquote>

<p>It's true that there are only two <em>named</em> women - but there is another <em>unnamed</em> woman on the passport! Here's the "Performing Arts" page:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/Performing-Arts.webp" alt="Passport page, richly illustrated, featuring Shakespeare's Globe. There are three actors in the corner." width="2048" height="1455" class="aligncenter size-full wp-image-70569">

<p>Shakespeare stares down at his Wooden O. Half the page is a stage, and the men and woman merely players.</p>

<p>Here they are in a bit more detail:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/actors.webp" alt="Close up of the actors. They are dressed in period costume and are emoting." width="1600" height="1520" class="aligncenter size-full wp-image-70570">

<p>Who are they? They look like reasonably modern photos rather than portraits. They're not obviously famous. None of the press at the time mentioned who they were. No stock photography library had anything similar that I could see. Your favourite AI thought one of them was Doctor Who and the other a Congressman from Nantucket.</p>

<p>The <a href="https://assets.publishing.service.gov.uk/media/5a7f516f40f0b62305b866a7/HMPO_magazine.pdf">official document describing the design</a> simply says:</p>

<blockquote><p>On the left hand side there is an image of the interior of the theatre, with a play in progress.</p></blockquote>

<p>I scanned in an old passport to get the faces in as much detail as possible. All three of them look like jobbing actors who you probably saw in a schools' production of Twelfth Night, don't they?
<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/actor-faces.webp" alt="Three faces in a row." width="699" height="233" class="aligncenter size-full wp-image-70575"></p>

<p>I couldn't find anything about them online. I asked my investigative-minded friends but they drew a blank.</p>

<p>I even sent a <a href="https://www.whatdotheyknow.com/request/images_used_in_2015_passport">Freedom of Information request to the Passport Office</a>.</p>

<p>They refused on grounds of GDPR, but they did say:</p>

<blockquote><p>However, we can disclose the photographs of the individuals appearing on the passport page captured by a photographer employed by a supplier contracted to HM Passport Office.</p></blockquote>

<p>So, if you're one of the actors / models - or know who they are - please drop a note in the box below!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70568&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/who-are-the-actors-in-the-uks-2015-passport/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[The UK Government's Low Value Purchase System is a Waste of Time]]></title>
		<link>https://shkspr.mobi/blog/2026/05/the-uk-governments-low-value-purchase-system-is-a-waste-of-time/</link>
					<comments>https://shkspr.mobi/blog/2026/05/the-uk-governments-low-value-purchase-system-is-a-waste-of-time/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 29 May 2026 11:34:54 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[FoI]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[statistics]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=69983</guid>

					<description><![CDATA[It can be hard running a small business. If you want to sell to a large organisation like the UK Government, there are forms to fill in, checks to comply with, tenders to bid on, and a hundred other things.  Luckily, there&#039;s the RM6237 Low Value Purchase System to make everything better. If a department wants to buy something below a certain threshold, they can contact any of the registered…]]></description>
										<content:encoded><![CDATA[<p>It can be hard running a small business. If you want to sell to a large organisation like the UK Government, there are forms to fill in, checks to comply with, tenders to bid on, and a hundred other things.</p>

<p>Luckily, there's the <a href="https://www.gca.gov.uk/agreements/RM6237">RM6237 Low Value Purchase System</a> to make everything better. If a department wants to buy something below a certain threshold, they can contact any of the registered suppliers and just buy it. No complicated paperwork, cheaper prices, win-win!</p>

<p>Except, there's on annoying bit of bureaucracy. Every month I have to tell the Government Commercial Agency what business I've done.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/GCA.webp" alt="Hello Terence Eden, It’s time to report your management information to the Government Commercial Agency (GCA). If you didn’t do any business, you still need to use this service to let us know. 9 April 2026 is the deadline to report your March 2026 data You need to report for the following commercial agreement(s):-   RM6237 – Low Value Purchase System Report your management information If you don’t think you should be getting this reminder or there is a problem reporting, please email the support team: Regards, GCA MI collection team" width="840" height="1000" class="aligncenter size-full wp-image-69985">

<p>Fair enough, I guess. Let them know how many paperclips I've sold to the Ministry of Administrative Affairs.</p>

<p>But there's a wrinkle. What if I've sold <em>nothing</em>? Well, I <strong>still</strong> have to log on, wait for an MFA code to be send, click through, and report "No Business".</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/Screenshot-20Confirm-report-no-business-for-March-2026-on-RM6237.webp" alt="Screenshot with a button to report no business." width="1300" height="500" class="aligncenter size-full wp-image-69988">

<p>I think that's a waste of time. But I wondered how much time it collectively wastes for the nation's small businesses.</p>

<p>So I filed <a href="https://www.whatdotheyknow.com/request/low_value_purchase_system_nill_r">a Freedom of Information request</a> to see how many people have to sign in to let them know they haven't done any business. They replied quickly - although sent the data as a PDF rather than the requested machine-readable format.</p>

<p>Here's how much of a waste of time it is for everyone:</p>

<table>
<thead>
<tr>
  <th align="right"><strong>Date</strong></th>
  <th align="right"><strong>Total Returns</strong></th>
  <th align="right"><strong>Nil Return</strong></th>
  <th align="right"><strong>Percent<wbr>age</strong></th>
</tr>
</thead>
<tbody>
<tr>
  <td align="right">Mar-25</td>
  <td align="right">768</td>
  <td align="right">729</td>
  <td align="right">94.9%</td>
</tr>
<tr>
  <td align="right">Apr-25</td>
  <td align="right">902</td>
  <td align="right">876</td>
  <td align="right">97.1%</td>
</tr>
<tr>
  <td align="right">May-25</td>
  <td align="right">948</td>
  <td align="right">923</td>
  <td align="right">97.4%</td>
</tr>
<tr>
  <td align="right">Jun-25</td>
  <td align="right">1,322</td>
  <td align="right">1,270</td>
  <td align="right">96.1%</td>
</tr>
<tr>
  <td align="right">Jul-25</td>
  <td align="right">1,406</td>
  <td align="right">1,355</td>
  <td align="right">96.4%</td>
</tr>
<tr>
  <td align="right">Aug-25</td>
  <td align="right">1,369</td>
  <td align="right">1,326</td>
  <td align="right">96.9%</td>
</tr>
<tr>
  <td align="right">Sep-25</td>
  <td align="right">1,416</td>
  <td align="right">1,362</td>
  <td align="right">96.2%</td>
</tr>
<tr>
  <td align="right">Oct-25</td>
  <td align="right">1,610</td>
  <td align="right">1,556</td>
  <td align="right">96.6%</td>
</tr>
<tr>
  <td align="right">Nov-25</td>
  <td align="right">1,713</td>
  <td align="right">1,654</td>
  <td align="right">96.6%</td>
</tr>
<tr>
  <td align="right">Dec-25</td>
  <td align="right">1,645</td>
  <td align="right">1,590</td>
  <td align="right">96.7%</td>
</tr>
<tr>
  <td align="right">Jan-26</td>
  <td align="right">1,536</td>
  <td align="right">1,487</td>
  <td align="right">96.8%</td>
</tr>
<tr>
  <td align="right">Feb-26</td>
  <td align="right">1,588</td>
  <td align="right">1,531</td>
  <td align="right">96.4%</td>
</tr>
</tbody>
</table>

<p>Even if you assume that it only takes 2 minutes to fill in their form, that's over 2 <em>days</em> worth of time being wasted every month.</p>

<p>At best, 59 small businesses reported that they sold something via RM6237. Well over a thousand businesses are clicking on a button which, frankly, ought not to exist. Why isn't the onus on those <em>buying</em> using the system to report what they've spent and who they spent it with?</p>

<p>After clicking the button, I'm always asked to rate my experience using the service. I FoI'd that data as well but was told:</p>

<blockquote><p>This information is not held. Feedback scores submitted are anonymised and only available as a service-wide view; consequently, we do not capture or hold results specific to RM6237</p></blockquote>

<p>So the GCA are wasting everyone's time and do not track how annoying it is.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=69983&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/the-uk-governments-low-value-purchase-system-is-a-waste-of-time/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Gadget Review: Chuwi Minibook X N150 + Linux ★★★★☆]]></title>
		<link>https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/</link>
					<comments>https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 27 May 2026 11:34:36 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[gadget]]></category>
		<category><![CDATA[laptop]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[review]]></category>
		<category><![CDATA[usb-c]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=68038</guid>

					<description><![CDATA[I needed a small and light laptop to take travelling. Something with a larger screen than my phone so I can use the Big Internet™. Nothing too expensive and something that uses the same USB-C charger as everything else.  So I settled on the Chuwi Minibook N150. It&#039;s literally small enough to fit in my cargo-short pockets. For the price (around £300ish) it is basically fine. There are a few ni…]]></description>
										<content:encoded><![CDATA[<p>I needed a small and light laptop to take travelling. Something with a larger screen than my phone so I can use the Big Internet™. Nothing too expensive and something that uses the same USB-C charger as everything else.</p>

<p>So I settled on the Chuwi Minibook N150. It's literally small enough to fit in my cargo-short pockets. For the price (around £300ish) it is basically fine. There are a few niggles, but none of them showstoppers for me.</p>

<p>I took it to OggCamp and had <em>so</em> many people come and ask me about it. It's a small, cute, and distinctive looking device.</p>

<p><a href="https://www.chuwi.com/product/items/chuwi-minibook-x-n150.html"><img src="https://shkspr.mobi/blog/wp-content/uploads/2026/05/minibook.webp" alt="A small laptop." width="1024" height="720" class="aligncenter size-full wp-image-71515"></a></p>

<h2 id="the-bad"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#the-bad">The Bad</a></h2>

<p>Here are the worst things about the laptop:</p>

<ul>
<li>US Keyboard. Yup, the @ and " are in the wrong place. I can be set to UK, but then you lose the <kbd>|</kbd> key.</li>
<li>The trackpad sometimes goes a bit jittery. It usually works, but once it a while goes askew. The touchscreen can be used if it happens.</li>
<li>Screen rotation works, but the keyboard and trackpad don't switch off if you bend the keyboard all the way back.</li>
<li>No biometrics like fingerprint or camera - so you need to remember your passwords.</li>
<li>Support from the manufacturer is haphazard. Mostly forum links and expired downloads. The firmware seems to update fine on Linux though.</li>
</ul>

<p>That's not too bad, I reckon.</p>

<h2 id="installing-linux"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#installing-linux">Installing Linux</a></h2>

<p>I had a brief play with Windows 11, let it update its drivers just in case there was any magic firmware, then nuked it.</p>

<p>Turn the device off. Turn it on and then hammer the <kbd>Delete</kbd> button. It'll pop you into the BIOS.</p>

<p>Secure Boot needs to be disabled:</p>

<p>Security → Secure Boot → Secure Boot → Disabled</p>

<p>You'll also need to set it to boot from a USB device:</p>

<p>Boot → Boot Option #1 → USB Device</p>

<p>The go to Save &amp; Exit.  I tried <a href="https://www.linuxmint.com/edition.php?id=325">Linux Mint Debian Edition</a>. It booted just fine and, after fiddling in the display settings, it automatically detected the screen rotation. Internet worked, touchscreen worked, Bluetooth worked. I tried a few distros and settled on NixOS as being the least worst option.</p>

<p>Everything works except the keyboard switching off when it is folded backwards.</p>

<h2 id="look-and-feel"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#look-and-feel">Look and Feel</a></h2>

<p>It is a solid lump of metal. There are no decals on back of the screen (so perfect for adding stickers!) and the bottom is similarly bare apart from some air-flow grilles and the usual identifying marks.</p>

<p>There are two USB-C ports on one side and a vestigial headphone jack on the other.</p>

<h2 id="keyboard"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#keyboard">Keyboard</a></h2>

<p>Despite coming from a UK warehouse and shipping with a UK plug, it has a US keyboard. The only real difference is the <code>£</code> symbol is missing from the <kbd>3</kbd> button, the <code>@</code> and <code>"</code> are swapped, and the <kbd>|</kbd> button is in the wrong place. None of that is disastrous and setting your OS to use a UK layout fixes things.</p>

<p>Because <kbd>\|</kbd> is mapped to <kbd>#~</kbd>, there's no way to type a backslash or pipe.</p>

<p>There are three levels of backlight. Off, dim, and not quite so dim. No fancy RBG effects here!</p>

<h2 id="trackpad"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#trackpad">Trackpad</a></h2>

<p>Supports multi-touch so you can use gestures. Obviously it is quite small, but you can touch the screen if you need to. Annoyingly, the trackpad is only "clicky" at the edges. You can click down in the middle, but it doesn't feel like it clicks. Not a show stopper, but a bit aggravating.</p>

<h2 id="screen"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#screen">Screen</a></h2>

<p>The screen has masked off rounded corners. Personally I think that's something which should be left to the Desktop Environment to decide. I can't really understand why they've done that. However, as the ratio is 16:10, you're not going to lose precious pixels when watching a movie.</p>

<p>The screen is bright enough for most uses and goes fairly dim for night use. It is locked at 50Hz which is a bit of a baffling decision. I guess it saves a modicum of power? For almost all uses, you won't notice the difference though.</p>

<h2 id="battery-and-charging"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#battery-and-charging">Battery and Charging</a></h2>

<p>It ships with a USB-C PD charger with a UK plug and a hard-wired connection. Unfortunately, the charger was limited to 36W - so fairly modest.</p>

<p>However, initially the Minibook would only charge at around 10W (20V⎓0.5A) eventually getting up to 16W (12V⎓1.3A or 20V⎓0.3A) - that didn't meaningfully change when I used a more powerful laptop charger. It never got up to the promised 36W while the unit was off.</p>

<p>Once I turned it on, it jumped to ~35W (11.70V⎓3A).  Using the stronger charger it occasionally got to 40W (20V⎓2A) but mostly stayed around 36W.</p>

<p>That's not a <em>bad</em> speed, and the battery is relatively small, but you won't be able to take it from empty to full with a quick blast. If you do need it to charge quickly, make sure it is on.</p>

<h2 id="size-weight-and-tablet-mode"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#size-weight-and-tablet-mode">Size, Weight, and Tablet Mode</a></h2>

<p>At just under a Kg, it is light enough to slip into a jacket pocket. Similarly, although around twice as thick as a normal 10 inch tablet, it isn't massive. Holding it up for long periods means you will feel the weight more keenly - but the keyboard acts as a pretty decent stand.</p>

<p>It supports multi-touch and a pen, apparently, which is not supplied.</p>

<h2 id="camera"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#camera">Camera</a></h2>

<p>The small lens is sensibly placed in the top centre and is of surprisingly good quality. You're not going to shoot a movie on it, but fine for video calls.</p>

<h2 id="verdict"><a href="https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/#verdict">Verdict</a></h2>

<p>Depending on how you are blessed by The Algorithm, this is around £300 - £350. You may also have to pay tax and delivery depending on where it is shipped from.</p>

<p>The <a href="https://www.chuwi.com/product/items/chuwi-minibook-x-n150.html">specifications are pretty decent</a>. Look, it's no MacBook Neo - but it is cheap and runs Linux.</p>

<p>If you're happy futzing around a bit, it's a decent travel companion.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=68038&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/gadget-review-chuwi-minibook-x-n150-linux/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Which age-gates should be skill-gates and vice-versa?]]></title>
		<link>https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/</link>
					<comments>https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 23 May 2026 11:34:31 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[politics]]></category>
		<category><![CDATA[thoughts]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=68406</guid>

					<description><![CDATA[In the UK, it is illegal to buy alcohol if you are under 18.  Similarly, in most countries, you cannot vote until you have reached a specific age.  These are age-gates. You do not need to prove your competence to drink, vote, smoke, or get married; you just need to be old enough.  Some things have skill-gates. If you want an amateur radio licence in the UK, you need to pass an exam. You can be…]]></description>
										<content:encoded><![CDATA[<p>In the UK, <a href="https://www.gov.uk/alcohol-young-people-law">it is illegal to buy alcohol if you are under 18</a>.</p>

<p>Similarly, in most countries, you cannot vote until you have reached a specific age.</p>

<p>These are age-gates. You do not need to prove your competence to drink, vote, smoke, or get married; you just need to be old enough.</p>

<p>Some things have skill-gates. If you want an amateur radio licence in the UK, you need to pass an exam. You can be any age<sup id="fnref:age"><a href="https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/#fn:age" class="footnote-ref" title="OK, realistically you have to be old enough to read, write, and communicate. But there's no legal barrier to a precocious 3 year old taking and passing the exams." role="doc-noteref">0</a></sup>.</p>

<p>Similarly, most jurisdictions allow you to get a medical licence once you have passed the requisite tests<sup id="fnref:doogie"><a href="https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/#fn:doogie" class="footnote-ref" title="As seen in the insightful documentary series &quot;Doogie Howser, M.D.&quot;" role="doc-noteref">1</a></sup>.</p>

<p>There are also activities which are dual-gated. You can only get a driving licence after passing a test, but you can only apply to take the test once you are a certain age.</p>

<p>Where should society swap age-gates and skill-gates?</p>

<p>Perhaps the big one is voting. The <a href="https://www.gov.uk/government/publications/representation-of-the-people-bill-policy-summaries/votes-at-16">UK is preparing to extend the franchise to all 16 and 17 year olds</a> - but why is there an age-gate at all?</p>

<p>Children are affected by politics, they pay tax on the goods they buy, they exist in the world. Why shouldn't they vote?</p>

<p>The <a href="https://shkspr.mobi/blog/2013/01/votes-for-children/">usual argument is that they are too immature</a>. But maturity isn't dependent on age. Idiots are allowed to vote. Centenarians with no stake in the consequences of their politics are allowed to vote. People who don't understand what powers a government has are allowed to vote.</p>

<p>Would it <em>really</em> be so bad to introduce a voting licence? Make people take a short quiz to ensure they understand what they're voting for and why they're voting.  Perhaps there are concerns about disenfranchising eligible adults (but not mature children) or that the state will rig the test (when they could rig the election) or whatever. But if we're sticking with the fiction that some people aren't mature enough to vote then we <em>must</em> give disenfranchised people a chance to prove their maturity.</p>

<p>You could make the same argument about driving. If a 7 year old is able to demonstrate mastery and control of a vehicle, are they likely to be a better driver than a 90 year old who has never taken a modern test?</p>

<p>Alcohol is different. We realise that the drug is harmful and <em>especially</em> harmful to developing humans. So we age-gate it. But do people really understand the health risks? Should you have to pass a test in order to imbibe? We make the people selling alcohol pass somewhat rigorous skills assessments. Perhaps the burden of proof should be reversed?</p>

<h2 id="wait-do-you-really-believe-all-this"><a href="https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/#wait-do-you-really-believe-all-this">Wait, do you really believe all this?</a></h2>

<p>No, not necessarily.</p>

<p>I find it fascinating that different cultures set different limits on people's activities. I wouldn't like to live somewhere that allowed anyone to drive on the public roads. Similarly, I don't particularly want governments restricting who can vote based on an arbitrary assessment.</p>

<p>But where are the limits? Why is the <a href="https://en.wikipedia.org/wiki/List_of_minimum_driving_ages">legal driving age so variable</a>? Why are some <a href="https://www.jalopnik.com/1988281/hardest-easiest-countries-to-get-drivers-license/">driving tests easier than others</a>?</p>

<p>Do you want a teenage doctor diagnosing you - even if they are legally certified? Should you be able to use a radio without passing a test if you're a legal adult?</p>

<p>Which age-gates and skill-gates do <em>you</em> think should be flipped?</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:age">
<p>OK, realistically you have to be old enough to read, write, and communicate. But there's no legal barrier to a precocious 3 year old taking and passing the exams.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/#fnref:age" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:doogie">
<p>As seen in the insightful documentary series "Doogie Howser, M.D."&nbsp;<a href="https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/#fnref:doogie" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=68406&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/which-age-gates-should-be-skill-gates-and-vice-versa/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Whale Fall]]></title>
		<link>https://shkspr.mobi/blog/2026/05/whale-fall/</link>
					<comments>https://shkspr.mobi/blog/2026/05/whale-fall/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 21 May 2026 11:34:15 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[technology]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70000</guid>

					<description><![CDATA[Somewhere, in the endless blue ocean, a gigantic mammal shudders as it takes its last breath. Thanks to science, we know that all dogs go to heaven, but all whales descend through the murky depths until their carcasses litter the seabed.  Imagine a giant dying. You can&#039;t. They are huge and endless. A towering presence which, so it seems, has always been part of our world. They dominate and are…]]></description>
										<content:encoded><![CDATA[<p>Somewhere, in the endless blue ocean, a gigantic mammal shudders as it takes its last breath. Thanks to science, we know that all dogs go to heaven, but all whales descend through the murky depths until their carcasses litter the seabed.</p>

<p>Imagine a giant dying. You can't. They are huge and endless. A towering presence which, so it seems, has <em>always</em> been part of our world. They dominate and are indomitable. It is simply unfathomable that they can ever end. Yet end they must.</p>

<p>As the whale dies, we do not know what passes through its cavernous brain. But we do know what the rest of the ocean thinks.</p>

<p>Lunch.</p>

<p>The death of a whale is a thing to be celebrated. The thump of their still-warm body onto the floor is the starting bell for a feast. Some larger predators sense an easy meal and tear off the choicest morsels. But what of the scavengers? What about the new life not yet established? What happens to the weird little creatures just waiting for an energy boost?</p>

<p>In many ways, it was fortuitous that Twitter pre-signalled its death with the Fail Whale.</p>

<p>The twitching corpse is gently floating down to its watery grave. Some of the older and more established social networks have bitten out chunks of the still-fresh body and have run away with their spoils. But the fascinating thing is watching all the <em>new</em> services benefit from the death of a giant. Mastodon, Discord, BlueSky, Qaplion, Nostr, and a bunch of others hollowing out the rotting husk and using it to power their own growth.</p>

<p>Will those .meow social networks ever become a gigaton behemoth capable of ruling the waves? Maybe not, but size is not the only metric of success. Finding and defending an ecological niche is its own reward. Evolution abhors a monoculture.</p>

<p>Several bloated bodies meander through the brine, each one confident that its ageless wisdom will outlast the others. Had they any self-awareness, the hubris would gnaw at their tattered souls until the crushing realisation of their impending doom drove them mad.</p>

<p>Perhaps it will happen to GitHub next. The endless downtime and forced injection of crappy AI will start a death spiral. Already established forges are waiting to pounce once they smell blood in the water. But what critters will emerge to suck the bones of the old giant and develop in unexpected ways? Some bizarre fungal growth will devour the stinking jelly unlocked from those shattered bones and a new ecosystem will emerge.</p>

<p>Will WordPress's increasingly erratic leadership and tangle of legal disputes cause it fatal damage? Once minnows darted away from its presence; now they cautiously nip at its greying skin. Its mighty bellow still echoes through the clammy waters, but there's a tinge of frailty in its song.</p>

<p>Everything dies eventually.</p>

<p>The internal flora and fauna - be they parasitic or symbiotic - eagerly await their host's downfall. A chance to break free and explore new strange new world. A chance to begin a new relationship and co-evolve in unexpected ways.</p>

<p>The biological pump is primed, the hungry jaws of an uncountable fleet of new ideas is just waiting to pounce, the giants swim on in blissful ignorance.</p>

<p>You can read more about <a href="https://en.wikipedia.org/wiki/Whale_fall">Whale Fall on Wikipedia</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70000&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/whale-fall/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[GDS weighs in on the NHS's decision to retreat from Open Source]]></title>
		<link>https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/</link>
					<comments>https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 17 May 2026 11:34:30 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[gds]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[nhs]]></category>
		<category><![CDATA[nhsx]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=71603</guid>

					<description><![CDATA[Within the UK&#039;s Civil Service you occasionally hear the expression &#34;being invited to a meeting without biscuits&#34;. It implies a rather frosty discussion without any of the polite niceties of a normal meeting. In general though, even when people have severe disagreements, it is rare for tempers to fray. It is even rarer for those internal disagreements to spill over into public.  Which is what…]]></description>
										<content:encoded><![CDATA[<p>Within the UK's Civil Service you occasionally hear the expression "being invited to a meeting <em>without</em> biscuits". It implies a <em>rather</em> frosty discussion without any of the polite niceties of a normal meeting<sup id="fnref:biscuits"><a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fn:biscuits" class="footnote-ref" title="Of course, all the budget cuts mean that biscuits cannot be purchased for any meetings. Which may explain some of the morale issues within the Civil Service. Thanks Austerity. Thausterity." role="doc-noteref">0</a></sup>. In general though, even when people have severe disagreements, it is rare for tempers to fray. It is even rarer for those internal disagreements to spill over into public.</p>

<p>Which is what makes GDS's latest guidance so surprising. At the start of the month, NHS England made the bizarre and irresponsible decision <a href="https://shkspr.mobi/blog/2026/05/nhs-goes-to-war-against-open-source/">to close all their Open Source repositories</a> due to unfounded fears of AI hacking<sup id="fnref:hack"><a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fn:hack" class="footnote-ref" title="As of today, they've shut down nearly 200 repositories. More may be coming." role="doc-noteref">1</a></sup>. Lots of people within the NHS were outraged. As were many outside - with <a href="https://keepthingsopen.com/">this petition</a> against the move gathering over 2,000 signatures.</p>

<p>Within other parts of government there was also alarm. Although I no longer work for Government Digital Service, I was contacted by several concerned people there who remembered all my work on Open Source. The brilliant team in Whitechapel have now published their guidance "<a href="https://www.gov.uk/guidance/ai-open-code-and-vulnerability-risk-in-the-public-sector">AI, open code and vulnerability risk in the public sector</a>".</p>

<p>It is <strong>brutal</strong>.</p>

<p>They utterly repudiate the NHS's stance and forensically eviscerate it. I'll let you read the whole thing, but here are a few choice excerpts:</p>

<blockquote><p>Recent public reporting about organisations restricting access to public repositories due to AI-enabled code analysis illustrates how quickly leaders may reach for blanket closure in response to uncertainty.</p></blockquote>

<p>Basically, non-technical managers need to stop over-reacting.</p>

<blockquote><p>Private repositories can create a false sense of security.</p></blockquote>

<p>I think that's the crux of the argument. Closing code doesn't solve the underlying problems.</p>

<blockquote><p>Making code private is not an appropriate mitigation for lack of ownership, patching capability, or operational assurance, so systems that cannot be safely maintained should be remediated or retired.</p></blockquote>

<p>If you are so concerned about the poor security of your systems, you should shut them down completely to mitigate the threat.</p>

<blockquote><p>Closure can become a one-way door.</p></blockquote>

<p>As I said to the BMJ, "<a href="https://www.bmj.com/content/393/bmj.s928">nothing lasts longer than a temporary fix</a>".</p>

<blockquote><p>Where code has been developed in the open, making a repository private later may not remove access for a capable adversary as popular repositories are often mirrored or forked</p></blockquote>

<p>Indeed. A friend of mine has already archived all of the NHS's repositories. You can <a href="https://github.com/orgs/uk-gov-mirror/repositories?q=mirror%3Afalse+fork%3Afalse+archived%3Afalse+nhs&amp;page=1">see the ones they've tried to hide</a>.</p>

<p>But the killer blow, I think, is this:</p>

<blockquote><p>Moving code from public to private as a substitute for investment in secure-by-design delivery, ownership and remediation is a warning sign because it reduces sharing and scrutiny, can slow coordinated improvement across government and suppliers, and does not remove the underlying weaknesses in a running service.</p></blockquote>

<p>Exactly! Coding in the open has been shown time and again to produce high quality and secure work. The looming threat of AI vulnerability scanners doesn't change that - security is a shared responsibility. Technical teams need to be well enough resourced to create secure systems; hiding code is as reliable as papering over structural cracks.</p>

<p>GDS was created was to be a <em>strong</em> centre with vast technology expertise. This was to counter the frankly shoddy approach to tech in other departments. Back then, a <a href="https://www.gov.uk/service-manual/service-assessments">Service Assessment</a> was a way for a department to prove that they were actually capable of designing, launching, and managing a complex IT project.</p>

<p>Most departments have become significantly better at the development and running of these sorts of projects, so the <i lang="fr">raison d'etre</i> of GDS has somewhat waned. Departments feel more confident in running off on their own. Usually I'd celebrate that - it's important that GDS doesn't become a bottleneck and that the talent is distributed throughout the whole Civil Service.</p>

<p>But NHS England has always been a bit of a weird one. One of the reasons NHSX was created<sup id="fnref:nhsx"><a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fn:nhsx" class="footnote-ref" title="I was there right before the start of NHSX and helped set it up." role="doc-noteref">2</a></sup> was to ensure that the health service had strong expertise in technology and its deployment. As the Head of Open Technology there, I helped craft the policies which embedded Open Source and Open Standards within it<sup id="fnref:open"><a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fn:open" class="footnote-ref" title="Which, I suppose, is why I'm bitter and angry that all our hard work is being undone." role="doc-noteref">3</a></sup>.</p>

<p>I don't know what discussions have taken place within NHS England - although <a href="https://www.whatdotheyknow.com/request/information_relating_to_guidance_2">I looking forward to receiving a response to my FOI request</a>. It looks to me like a small group within NHS England have received a report showing some potential vulnerabilities discovered by Mythos. Rather than following their own internal guidance, they've over-reacted and slapped a blanket ban on coding in the open.</p>

<p>I fervently hope that this new guidance will encourage DHSC to bring NHS England into line with best practice. If not, perhaps GDS ought to reassert itself as the technical authority with power to veto a department's incomprehensible decisions?</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:biscuits">
<p>Of course, all the budget cuts mean that biscuits cannot be purchased for <em>any</em> meetings. Which may explain some of the morale issues within the Civil Service. Thanks Austerity. Thausterity.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fnref:biscuits" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:hack">
<p>As of today, they've shut down nearly 200 repositories. More may be coming.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fnref:hack" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:nhsx">
<p>I was there right before the start of NHSX and helped set it up.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fnref:nhsx" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:open">
<p>Which, I suppose, is why I'm bitter and angry that all our hard work is being undone.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/#fnref:open" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=71603&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/gds-weighs-in-on-the-nhss-decision-to-retreat-from-open-source/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[NHS Goes To War Against Open Source]]></title>
		<link>https://shkspr.mobi/blog/2026/05/nhs-goes-to-war-against-open-source/</link>
					<comments>https://shkspr.mobi/blog/2026/05/nhs-goes-to-war-against-open-source/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 01 May 2026 11:44:04 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[nhs]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[politics]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70760</guid>

					<description><![CDATA[The NHS is preparing to close nearly all of its Open Source repositories.  Throughout my time working for the UK Government - in GDS, NHSX, i.AI, and others - I championed Open Source. I spoke to dozens of departments about it, wrote guidance still in use today, and briefed Ministers on why it was so important.  That&#039;s why I&#039;m beyond disappointed at recent moves from NHS England to backtrack on…]]></description>
										<content:encoded><![CDATA[<p>The NHS is preparing to close nearly <em>all</em> of its Open Source repositories.</p>

<p>Throughout my time working for the UK Government - in GDS, NHSX, i.AI, and others - I championed Open Source. I spoke to dozens of departments about it, wrote guidance still in use today, and briefed Ministers on why it was so important.</p>

<p>That's why I'm beyond disappointed at recent moves from NHS England to backtrack on all the previous commitments they've made about the value of open source to the UK's health service.</p>

<p>It's rare that multiple people leak the same story to me, but that's what gives me confidence that lots of people within the NHS are aghast at this news.</p>

<p>A few days ago, I was sent this quote which was attributed to a senior technical person in NHS England.</p>

<blockquote><p>We are obviously looking at things like Mythos, which is more sophisticated at finding vulnerabilities. In the next week or so, we will be changing our tack on coding the open and making our code public until we're on top of that risk.</p>

<p>Most of our repos, unless they're essential, will be removed for security reasons.</p></blockquote>

<p>As I've written before, <a href="https://shkspr.mobi/blog/2026/04/does-mythos-mean-you-need-to-shut-down-your-open-source-repos/">this is not the correct response to the purported threat by Mythos</a>.  Neither the AI Safety Institute nor the NCSC recommend this action.  While there may be some increase in risk from AI security scanners, to shutter everything would be a gross overreaction.</p>

<p>Nevertheless, that's what the NHS is preparing to do.</p>

<p>On the 29th of April, guidance note SDLC-8 was sent out. Here's what it says:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/SDLC-8.webp" alt="All source code repositories must be private by default. Repositories may be internal where there is a legitimate need for visibility within the enterprise. Repositories must not be public unless there is an explicit and exceptional need, and public access has been formally approved by the Engineering Board. Purpose Public repositories materially increase the risk of unintended disclosure of source code, architectural decisions, configuration detail, and contextual information that may be exploited — particularly given rapid advancements in Al models capable of large-scale code ingestion, inference, and reasoning (e.g. developments such as the Mythos model). This red line establishes a default-closed posture for code while the organisation assesses the impact of these changes and ensures that any public publication of code is a deliberate, reviewed, and justified decision. • For P&amp;P Public repositories we will switch to Private on Monday the 11th May 2026 • Teams that have a need for an exemption need to declare this to the Engineering mailbox by COP Wednesday 6th May 2026 • Teams can change to private at any time ahead of this • Central tracking of public repositories: NHSE public repositories.xlsx" width="1400" height="400" class="aligncenter size-full wp-image-70761">

<p>The majority of <a href="https://github.com/nhsuk/">code repos published by the NHS</a> are not meaningfully affected by any advance in security scanning. They're mostly data sets, internal tools, guidance, research tools, front-end design and the like. There is <em>nothing</em> in them which could realistically lead to a security incident.</p>

<p>When I was working at NHSX during the pandemic, we were so confident of the safety and necessity of open source, we made sure <a href="http://web.archive.org/web/20230122050346/https://transform.england.nhs.uk/blogs/code-behind-nhs-covid-19-app/">the Covid Contact Tracing app was open sourced the minute it was available to the public</a>. That was a nationally mandated app, installed on millions of phones, subject to intense scrutiny from hostile powers - and yet, despite publishing the code, architecture and documentation, the open source code caused <strong>zero</strong> security incidents.</p>

<p>Furthermore, this new guidance is in direct contradiction to the UK's <a href="https://www.gov.uk/guidance/the-technology-code-of-practice#be-open-and-use-open-source">Tech Code of Practice point 3 "Be open and use open source"</a> which insists on code being open.</p>

<p>Similarly, the <a href="https://www.gov.uk/service-manual/technology/making-source-code-open-and-reusable">Service Standard says</a>:</p>

<blockquote><p>There are very few examples of code that must not be published in the open.</p>

<p>The main reason for code to be closed source is when it relates to policy that has not yet been announced. In this case, you must make the code open as soon as possible after the policy is published.</p>

<p>You may also need to keep some code closed for security reasons, for example code that protects against fraud. Follow the guidance on <a href="https://gov.uk/government/publications/open-source-guidance/when-code-should-be-open-or-closed">code you should keep closed</a> and <a href="https://gov.uk/government/publications/open-source-guidance/security-considerations-when-coding-in-the-open">security considerations for open code</a>.</p></blockquote>

<p>There's also the DHSC policy "<a href="https://www.gov.uk/government/publications/data-saves-lives-reshaping-health-and-social-care-with-data/data-saves-lives-reshaping-health-and-social-care-with-data">Data saves lives: reshaping health and social care with data</a>":</p>

<blockquote><p>Commitment 601 – completed May 2022</p>

<p>We will publish a digital playbook on how to open source your code for health and care organisations</p></blockquote>

<p>And, here's NHS Digital's stance on open source in their <a href="https://github.com/NHSDigital/software-engineering-quality-framework/blob/main/practices/open-source.md">Software Engineering Quality Framework</a>:</p>

<blockquote><p>The position of all three of these documents is that we should code in the open by default.</p></blockquote>

<p>All of which is reflected in the <a href="https://service-manual.nhs.uk/standards-and-technology/service-standard-points/12-make-new-source-code-open">NHS service standard</a>:</p>

<blockquote><p>Public services are built with public money. So unless there's a good reason not to, the code they're based should be made available for other people to reuse and build on.</p></blockquote>

<p>All of which is to say - open source should be baked into the DNA of the NHS by now. There are <em>thousands</em> of NHS repositories on GitHub. The work undertaken to assess all of them and then close them will be massive. And for what?</p>

<p>Even if we ignore the impracticality of closing all the code - it is too late! All that code has already been slurped up. If Mythos really is the ultimate hacker, hiding the code now does nothing. It has likely already retained copies of the repositories.</p>

<p>And if it were both practical and effective to hide source code - that doesn't matter. These AI tools are just as effective against closed-source. They can analyse binaries and probe websites with ease.</p>

<p>There are tens of thousands of NHS website pages which <a href="https://duckduckgo.com/?q=github+site%3Anhs.uk">refer to their GitHub repos</a> - will they all need to be updated? What's the cost of that?</p>

<p>I've no idea what led to NHS England making this retrograde decision - <a href="https://www.whatdotheyknow.com/request/information_relating_to_guidance_2">so I've send a Freedom of Information request to find out</a>.</p>

<p>I am convinced that closing all their excellent open source work is the wrong move for the NHS. I hope they see sense and reverse course.</p>

<p>Until then, I've helped make sure that <em>every single NHS repository</em> has been backed up and, because the software licence permits it, can be re-published if the original is closed.</p>

<p>In the meantime, <a href="https://www.writetothem.com/">you should email your MP</a> and tell them that the NHS is wrong to shutter its world-leading open source repositories.</p>

<p>Don't let them take away your right to see the code which underpins our nation's healthcare.</p>

<hr>

<h3 id="further-reading"><a href="https://shkspr.mobi/blog/2026/05/nhs-goes-to-war-against-open-source/#further-reading">Further Reading</a></h3>

<ul>
<li>I'm quoted in this <a href="https://www.newscientist.com/article/2524962-nhs-england-rushes-to-hide-software-over-ai-hacking-fears/">article from The New Scientist</a>.</li>
<li><a href="https://www.linkedin.com/feed/update/activity:7456332994920837120?trk=feed_main-feed-card_social-actions-comments">Matt Hancock on the issue</a></li>
<li><a href="https://www.linkedin.com/posts/jessicarosemorley_i-have-been-a-long-time-champion-for-open-ugcPost-7457048384449761280-6_Xg">Discussion by Jessica Morley, PhD</a></li>
<li><a href="https://fsfe.org/news/2026/news-20260504-01.en.html">Free Software Foundation Europe press release</a></li>
<li><a href="https://www.newscientist.com/article/2525315-backlash-builds-over-nhs-plan-to-hide-source-code-from-ai-hacking-risk/">Further commentary from New Scientist</a></li>
<li><a href="https://keepthingsopen.com/">Petition - Keep Things Open</a></li>
<li><ins datetime="2026-05-14">Update 2026-05-14</ins>: GDS have published their <a href="https://www.gov.uk/guidance/ai-open-code-and-vulnerability-risk-in-the-public-sector">Guidance "AI, open code and vulnerability risk in the public sector "</a> which explicitly says closing repos is the wrong approach.</li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70760&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/nhs-goes-to-war-against-open-source/feed/</wfw:commentRss>
			<slash:comments>44</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Get all the reactions to your GitHub content using GraphQL]]></title>
		<link>https://shkspr.mobi/blog/2026/02/get-all-the-reactions-to-your-github-content-using-graphql/</link>
					<comments>https://shkspr.mobi/blog/2026/02/get-all-the-reactions-to-your-github-content-using-graphql/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 05 Feb 2026 12:34:21 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[GraphQL]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=67577</guid>

					<description><![CDATA[I am both vain and prurient. A combination which makes me fun at parties and a delight to know.  Sometimes when I raise an issue on GitHub, or write a comment, other users leave me Emoji reactions. Perhaps a 👍 or 🎉 if they like my contribution, but occasionally a 👎 or 😕 if they&#039;re foolish enough to think I&#039;m wrong.  The problem is, GitHub doesn&#039;t tell me that someone has 🚀&#039;d my wisdom. If GitHub w…]]></description>
										<content:encoded><![CDATA[<p>I am both vain <em>and</em> prurient. A combination which makes me fun at parties and a delight to know.</p>

<p>Sometimes when I raise an issue on GitHub, or write a comment, other users leave me Emoji reactions. Perhaps a 👍 or 🎉 if they like my contribution, but occasionally a 👎 or 😕 if they're foolish enough to think I'm wrong.</p>

<p>The problem is, GitHub doesn't tell me that someone has 🚀'd my wisdom. If GitHub was as good as Facebook, it would present a little 🔔 to let me know exactly how many ❤️s I have received. Instead I have to manually check every issue I've raised to see if the hive-mind judges me worthy.</p>

<p>You might be thinking that there's an API for finding the reaction count to a specific piece of content - and you'd be right! The only problem is that <a href="https://docs.github.com/en/rest/reactions/reactions?apiVersion=2022-11-28">it requires you to send it a <em>specific</em> content ID</a>. So pretty bloody useless unless you want to construct a mega-query of everything you've ever written.</p>

<p>Enter the terrifying world of <a href="https://docs.github.com/en/graphql">GraphQL</a> - where men fear to tread and AIs are driven mad. It is possible to squeeze the API until the pips squeak. Here's a GraphQL query, run using the <code>gh</code> CLI, which grabs any issue with over zero reactions, displays how many reactions it received, and who gave what sort of reaction.</p>

<pre><code class="language-bash">gh api graphql -f query='
query {
  search(query: "author:@me reactions:&gt;0", type: ISSUE, first: 10) {
    nodes {
      ... on Issue {
        url
        reactions(last: 50) {
          totalCount
          nodes {
            content
            user {
              login
            }
          }
        }
      }
    }
  }
}'
</code></pre>

<p>As you might be able to decipher, that looks for the 10 most recent issues. If you are prolific, you may want to increase that number - although it will increase the time it takes for the query to run. If you have the temerity to dare to retrieve more than 100, you'll be slapped with the dreaded <code>EXCESSIVE_PAGINATION</code> error.</p>

<p>Similarly, it only gets the most recent 50 reactions. The count will be be the total number of reactions, no matter how low you set the number.</p>

<p>In return, you'll get a hideous mass of JavaScript which looks like it has been vomited up by a disgruntled Cacodemon:</p>

<pre><code class="language-json">{
  "data": {
    "search": {
      "nodes": [
       {
          "url": "https://github.com/validator/validator/issues/1814",
          "reactions": {
            "totalCount": 9,
            "nodes": [
              {
                "content": "THUMBS_UP",
                "user": {
                  "login": "markohoza"
                }
              },
              {
                "content": "EYES",
                "user": {
                  "login": "adamwolf"
                }
              },
</code></pre>

<p>There is no way to get anything older. If someone liked a comment you made in 2019, you will <em>never</em> know!</p>

<p>If you hate your eyes enough to read through <a href="https://docs.github.com/en/graphql/reference/enums#searchtype">the search type documentation</a>, you'll notice there is no way to search Pull Requests. This is, of course, a rotten lie. If you read <a href="https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests#search-only-issues-or-pull-requests">different documentation</a> you'll see that PRs are classed as a type of issue. Why? Because your sanity is not worth the cost of updating things.</p>

<p>Anyway, it makes our life slightly easier. We can search both Issues and PRs in one easy to chew lump of GraphQL:</p>

<pre><code class="language-bash">gh api graphql -f query='
query {
  search(query: "author:@me reactions:&gt;0", type: ISSUE, first: 100) {
    nodes {
      ... on Issue {
        url
        reactions(last: 100) {
          totalCount
          nodes {
            content
            user {
              login
            }
          }
        }
      }
      ... on PullRequest {
        url
        reactions(last: 100) {
          totalCount
          nodes {
            content
            user {
              login
            }
          }
        }
      }
    }
  }
}'
</code></pre>

<p>Again, beware gazing into the JSON lest the JSON gazes into <em>you!</em></p>

<pre><code class="language-json">{
  "data": {
    "search": {
      "nodes": [
        {
          "url": "https://github.com/WICG/webmonetization/pull/634",
          "reactions": {
            "totalCount": 2,
            "nodes": [
              {
                "content": "CONFUSED",
                "user": {
                  "login": "tomayac"
                }
              },
              {
                "content": "HEART",
                "user": {
                  "login": "tomayac"
                }
              }
            ]
          }
        },
</code></pre>

<p>OK, so it should be pretty damned simple to get the number of reactions to any comments, right? RIGHT?!?!</p>

<p>No. Because consistency is a dirty word and GraphQL was designed in the bowels of hell as a way to keep API developers from ever obtaining a state of grace.</p>

<p>There's no way I could find to use <code>reactions:&gt;0</code> with a comment search query. This will get you lots of useless unreacted results. I guess you can filter them with <code>jq</code> or just scratch your monitor with razor blades so you don't have to see their empty laughing maws.</p>

<pre><code class="language-bash">gh api graphql -f query='
query {
  viewer {
    issueComments(last: 10) {
      nodes {
        url
        reactions(last: 10) {
          totalCount
          nodes {
            content
            user {
              login
            }
          }
        }
      }
    }
  }
}'
</code></pre>

<p>And, again, JSON nested like wheels within wheels and fires within fires:</p>

<pre><code class="language-json">{
  "data": {
    "viewer": {
      "issueComments": {
        "nodes": [
          {
            "url": "https://github.com/home-assistant/supervisor/issues/6474#issuecomment-3740347148",
            "reactions": {
              "totalCount": 0,
              "nodes": []
            }
          },
          {
            "url": "https://github.com/edent/3D-UK-Money/issues/1#issuecomment-3757022146",
            "reactions": {
              "totalCount": 1,
              "nodes": [
                {
                  "content": "THUMBS_UP",
                  "user": {
                    "login": "MickeyF2010"
                  }
                }
              ]
            }
          },
</code></pre>

<h2 id="what-have-we-learned-today"><a href="https://shkspr.mobi/blog/2026/02/get-all-the-reactions-to-your-github-content-using-graphql/#what-have-we-learned-today">What Have We Learned Today?</a></h2>

<p>The Necronomicon was probably written in GraphQL. Any form of Daemon summoning <em>must</em> use nested queries and frightening syntax.</p>

<p>Trying to track reactions to your content <em>will</em> drive you mad. There's a reason this knowledge is forbidden.</p>

<h2 id="disclaimer"><a href="https://shkspr.mobi/blog/2026/02/get-all-the-reactions-to-your-github-content-using-graphql/#disclaimer">Disclaimer</a></h2>

<p>This post was not sponsored by GitHub. Although I did drink rather too many of their free beers at FOSDEM. Consider this post payback for that self-induced hangover.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=67577&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/02/get-all-the-reactions-to-your-github-content-using-graphql/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Extracting Video from Motion Photos on Linux]]></title>
		<link>https://shkspr.mobi/blog/2025/12/extracting-video-from-motion-photos-on-linux/</link>
					<comments>https://shkspr.mobi/blog/2025/12/extracting-video-from-motion-photos-on-linux/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 28 Dec 2025 12:34:22 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[exif]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[photos]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=66565</guid>

					<description><![CDATA[Modern Android cameras can take &#34;Motion Photos&#34;. They capture a few seconds of video from before and after you hit the shutter button. You can then either select the bit of the photo where no-one is blinking, or you can send the whole thing as a little movie.  Some apps (like WhatsApp) will play the motion photo when the image is selected, others will just show a static image.  So how do you…]]></description>
										<content:encoded><![CDATA[<p>Modern Android cameras can take "Motion Photos". They capture a few seconds of video from before and after you hit the shutter button. You can then either select the bit of the photo where no-one is blinking, or you can send the whole thing as a little movie.</p>

<p>Some apps (like WhatsApp) will play the motion photo when the image is selected, others will just show a static image.</p>

<p>So how do you extract the movie from the image using Linux?</p>

<p>Step one, let's take a look at the EXIF metadata in the image. Here's what running <code>exiftool photo.MP.jpg</code> gets:</p>

<pre><code class="language-_">Motion Photo                    : 1
Motion Photo Version            : 1
Motion Photo Presentation Timestamp Us: 866808
Directory Item Mime             : image/jpeg, image/jpeg, video/mp4
Directory Item Semantic         : Primary, GainMap, MotionPhoto
Directory Item Length           : 46353, 2106347
Directory Item Padding          : 0
MPF Version                     : 0100
Number Of Images                : 2
MP Image Flags                  : (none)
MP Image Format                 : JPEG
MP Image Type                   : Undefined
MP Image Length                 : 46353
MP Image Start                  : 2570425
</code></pre>

<p>That can be cross-referenced with the <a href="https://developer.android.com/media/platform/motion-photo-format">Motion Photo metadata specification</a>.</p>

<p>We can confirm this is a Motion Photo, Version 1. The video portion at 866,808 microseconds (about 0.8 seconds) is where the main photo is taken from.</p>

<p>The file starts with the image, then a GainMap (for HDR), and then the video.</p>

<p>Somewhat obtusely (in my opinion) the Directory Item Length only shows "secondary media items" - in this case, the GainMap and Video.</p>

<p>The filesize is 4,723,125 bytes, which equals the sum of the three values; 46,353 + 2,106,347 + 2,570,425.</p>

<p>So, to get the MP4 video, we need to extract the <em>last</em> 2,106,347 bytes. This can be double-checked by taking the filesize and subtracting the MP Image Start and the MP Image Lengths (4,723,125 - 46,353 - 2,570,425 = 2,106,347).</p>

<p>The extraction can be done with <code>dd</code> but it's probably just as easy to use <code>tail</code> to read the last N bytes of a file:</p>

<p><code>tail -c 2106347 photo.MP.jpg &gt; video.mp4</code></p>

<p>You can verify that the video is valid by running <code>ffmpeg -i video.mp4</code> - the output will be lower resolution than the photo and will only be a few seconds long. It will play in VLC or any other standard player.</p>

<h2 id="try-it-yourself"><a href="https://shkspr.mobi/blog/2025/12/extracting-video-from-motion-photos-on-linux/#try-it-yourself">Try It Yourself</a></h2>

<p>Here's one of my motion photos - it should present in your browser as a still image, but run the above code to extract the video.</p>

<p><a href="https://shkspr.mobi/blog/wp-content/uploads/2025/12/PXL_20251220_224052239.MP_.bk.jpg"><img src="https://shkspr.mobi/blog/wp-content/uploads/2025/12/PXL_20251220_224052239.MP_.jpg" alt="Photo of a wind turbine." width="3072" height="4080" class="aligncenter size-full wp-image-66570"></a></p>

<p>Click the photo to download the full version rather than the optimised one.</p>

<h2 id="sources"><a href="https://shkspr.mobi/blog/2025/12/extracting-video-from-motion-photos-on-linux/#sources">Sources</a></h2>

<p>For other adventures in Motion Photo exploration, take a look at:</p>

<ul>
<li><a href="https://developer.android.com/media/platform/motion-photo-format">https://developer.android.com/media/platform/motion-photo-format</a></li>
<li><a href="https://motion-live.js.org/">https://motion-live.js.org/</a></li>
<li><a href="https://medium.com/android-news/working-with-motion-photos-da0aa49b50c">https://medium.com/android-news/working-with-motion-photos-da0aa49b50c</a></li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=66565&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/12/extracting-video-from-motion-photos-on-linux/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Toshiba / Vestel Engineering Menu - 4725]]></title>
		<link>https://shkspr.mobi/blog/2020/01/toshiba-vestel-engineering-menu-4725/</link>
					<comments>https://shkspr.mobi/blog/2020/01/toshiba-vestel-engineering-menu-4725/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 27 Jan 2020 12:47:42 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[tv]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=31349</guid>

					<description><![CDATA[Here&#039;s a quick guide to hacking investigating your TV&#039;s engineering menu. This works on all Vestel TVs - including modern Toshiba screens.  I&#039;ve also written about Telnet control of Toshiba Smart TVs.  If you manage to break your TV using this forbidden knowledge, please don&#039;t come crying to me for help.   Turn on your TV. Switch to an HDMI source. You must not be on a TV menu. Hold down the 0…]]></description>
										<content:encoded><![CDATA[<p>Here's a quick guide to <del>hacking</del> investigating your TV's engineering menu. This works on all Vestel TVs - including modern Toshiba screens.  I've also written about <a href="https://shkspr.mobi/blog/2018/11/telnet-control-of-toshiba-smart-tvs/">Telnet control of Toshiba Smart TVs</a>.</p>

<p>If you manage to break your TV using this forbidden knowledge, please don't come crying to me for help.</p>

<ol>
<li>Turn on your TV.</li>
<li>Switch to an HDMI source. You must not be on a TV menu.</li>
<li>Hold down the <code>0</code> button until you see the message "Remote controller will control TV"</li>
<li>Press the blue 'Home' button on the remote control.</li>
<li>Press the following buttons on the remote control number pad, in this order

<ul>
<li><code>4</code></li>
<li><code>7</code></li>
<li><code>2</code></li>
<li><code>5</code></li>
</ul></li>
</ol>

<p>You should be presented with this screen:
<img src="https://shkspr.mobi/blog/wp-content/uploads/2020/01/Toshiba-Service-Menu.jpg" alt="A blue screen full of debug information." width="1024" height="556" class="aligncenter size-full wp-image-33648"></p>

<p>The options will vary depending on your TV model.</p>

<ul>
<li>Video Settings

<ul>
<li>Whole bunch of things like <code>RF AGC SECAM</code> and <code>ADC Calibration B Offset</code></li>
<li>This is a great way to break your TV.</li>
</ul></li>
<li>Audio Settings

<ul>
<li>Just displays the "Surround Type" - you can't change anything.</li>
</ul></li>
<li>Options 1

<ul>
<li>Power-up settings, hotel mode, volume. Again, read-only.</li>
</ul></li>
<li>Options 2

<ul>
<li>Information about menus, HMDI selection, DCF ID. Yup, nothing to play with.</li>
</ul></li>
<li>Options 3

<ul>
<li>More diagnostic information about smart TV stuff. Includes Alexa Ready state.</li>
</ul></li>
<li>Tuning Settings

<ul>
<li>Tuner type and firmware</li>
</ul></li>
<li>Source Settings

<ul>
<li>Which sources have been enabled</li>
</ul></li>
<li>Diagnostic

<ul>
<li>Remote Control Test - see which buttons you're pressing on the remote</li>
<li>Video Pattern Test - pressing right cycles through white, red, green, blue, magenta, turquoise, yellow, grey, black</li>
<li>Factory Reset</li>
<li>Some more read-only stuff like MAC address</li>
</ul></li>
<li>USB Logging

<ul>
<li>Screen Capture - can be set to Enabled. No idea how to activate it though</li>
<li>UART RX - can be Enabled</li>
<li>Flash write debug - seems to write a debug list to a USB drive</li>
<li>HTTP Test Server - can be Enabled.</li>
<li>Export channel list to USB</li>
</ul></li>
<li>USB Operations

<ul>
<li>Only works if you have a USB drive connected - but doesn't seem to do anything.</li>
</ul></li>
</ul>

<p>After turning on the test server, the following ports were exposed:</p>

<pre><code class="language-_">PORT      STATE SERVICE
2870/tcp  open  daishi
5001/tcp  open  commplex-link
7681/tcp  open  unknown
56183/tcp open  unknown
56789/tcp open  unknown
56790/tcp open  unknown
</code></pre>

<p>There are some weird entries in the debug log written to USB:</p>

<pre><code class="language-_">mbrg_AUDIO_HDMI_MODE_CONFIG : NONPCM mode 
[AUDIO][Utopia]: ===== Check Audio Decoder Protection from hash-key IP =====
[AUDIO][Utopia]: Hash Key Check DD Fail, no DD license!!
[AUDIO][Utopia]: Hash Key Check DDP Fail, no DD+ license!!
[AUDIO][Utopia]: Hash Key Check Dolby MS11 Fail, no Dolby MS11 license!!
[AUDIO][Utopia]: Hash Key Check Dolby MS12 LC profile Fail, no Dolby MS12 LC profile license!!
[AUDIO][Utopia]: Hash-key Support Dolby MS12 D profile.
[AUDIO][Utopia]: Hash Key Check Dolby MS12 B profile Fail, no Dolby MS12 B profile license!!
[AUDIO][Utopia]: Hash Key Check AAC Fail, no any AAC license!!
[AUDIO][Utopia]: Hash Key Check DDCO Fail, no DDCO license!!
[AUDIO][Utopia]: Hash Key Check DTS Fail, no DTS license!!
[AUDIO][Utopia]: Hash-key Support WMA.
[AUDIO][Utopia]: Hash Key Check DRA Fail, no DRA license!!
[AUDIO][Utopia]: Hash Key Check DTSLBR Fail, no DTSLBR license!!
[AUDIO][Utopia]: Hash Key Check DTSE Fail, no DTSE license!!
[AUDIO][Utopia]: Hash Key Check DTSNeoUltra Fail, no DTSNeoUltra license!!
[AUDIO][Utopia]: Hash-key Support SRS_TSHD.
[AUDIO][Utopia]: Hash Key Check SRS_THEATERSOUND Fail, no SRS_THEATERSOUND license!!
[AUDIO][Utopia]: Hash Key Check DTS_StudioSound3D Fail, no DTS_StudioSound3D license!!
[AUDIO][Utopia]: Hash Key Check COOK Fail, no COOK license!!
[AUDIO][Utopia]: Hash-key Support DTS_HD.
[AUDIO][Utopia]: Hash Key Check Dolby volume Fail, no Dolby volume license!!
[AUDIO][Utopia]: Hash Key Check SRS_PURESND Fail, no SRS_PURESND license!!
[AUDIO][Utopia]: Hash Key Check DTS VirtualX Fail, no DTS VirtualX license!!
[AUDIO][Utopia]: Hash Key Check DTS_StudioSound_II Fail, no DTS_StudioSound_II license !!
[AUDIO][Utopia]: ===== Check Protection IP End                         =====
</code></pre>

<p>Right, that's it. Hope that's of use to someone.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=31349&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2020/01/toshiba-vestel-engineering-menu-4725/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
	</channel>
</rss>
