<?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>Wed, 13 May 2026 14:40:21 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</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[Stupidly Simple SVG Sparklines]]></title>
		<link>https://shkspr.mobi/blog/2026/05/stupidly-simple-svg-sparklines/</link>
					<comments>https://shkspr.mobi/blog/2026/05/stupidly-simple-svg-sparklines/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 13 May 2026 11:34:01 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[svg]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=63359</guid>

					<description><![CDATA[A sparkline is a little line-graph with no axes or other unnecessary details. They&#039;re useful for getting quick understanding of what the data is showing.  They&#039;re also really easy to create programmatically.    This uses the SVG &#34;polyline&#34; which takes a list of x,y co-ordinate pairs. But can you spot the small problem?  &#60;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 1024 124&#34;&#62;     &#60;polyline …]]></description>
										<content:encoded><![CDATA[<p>A sparkline is a little line-graph with no axes or other unnecessary details. They're useful for getting quick understanding of what the data is showing.</p>

<p>They're also <em>really</em> easy to create programmatically.</p>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 124"><polyline fill="none" stroke="#0074D9" stroke-width="3" points="12,48
83,84
154,79
226,90
297,79
369,65
440,78
512,80
583,88
654,12
726,56
797,92
869,93
940,97
1012,106"></polyline></svg>

<p>This uses the SVG "<a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polyline">polyline</a>" which takes a list of x,y co-ordinate pairs. But can you spot the small problem?</p>

<pre><code class="language-svg">&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 124"&gt;
    &lt;polyline fill="none" stroke="#0074D955" stroke-width="3" 
        points="12,48 83,84 154,79 226,90 297,79 369,65 440,78 512,80 583,88 654,12 726,56 797,92 869,93 940,97 1012,106"&gt;&lt;/polyline&gt;
&lt;/svg&gt;
</code></pre>

<p>The SVG co-ordinate system has position 0,0 at the top <em>left</em>. Most graphics formats are like that. That's fine for our x value - but it means higher y values will appear <em>lower</em> on the graph.</p>

<p>Getting the x co-ordinate of each data point is easy. Take the width of the SVG image and divide it by the number of data-points.</p>

<p>The y co-ordinate is harder. The algorithm is:</p>

<ol>
<li>Find the height of the SVG.</li>
<li>Find the maximum value in the data.</li>
<li>Find the minimum value in the data.</li>
<li>Divide the maximum value by the height of the graph.</li>
<li>For each data point, either:

<ul>
<li>To have the lowest value at the bottom of the graph, subtract the minimum from the value, then multiply by the ratio in (4).</li>
<li>Or, to retain the gap between zero and the lowest value, multiply the value by the ratio in (4).</li>
</ul></li>
<li>The y co-ordinate is calculated by subtracting the value in (5) from the height in (1).</li>
</ol>

<p>Here's some code showing how it works. I've added a little padding to the inside of the graph - you'll see why later:</p>

<pre><code class="language-php">//  Max and min of views.
$max_views = max( $svg_views_data );
$min_views = min( $svg_views_data );
$svg_data_length = sizeof( $svg_dates_data ) - 1;

//  SVG details for scaling.
$svg_padding = 12;
$svg_width_graph  = 1000;
$svg_width  = $svg_width_graph + ( $svg_padding * 2 );
$svg_height_graph = 100;
$svg_height = $svg_height_graph + ( $svg_padding * 2 );

//  Calculate where each point should be.
$x_per = $svg_width_graph / ( $svg_data_length );
$y_per = $svg_height_graph / $max_views;

//  Loop through the data.
foreach ( $svg_views_data as $index=&gt;$views ) {
    //  X is from the left.
    $x_pos = intval( $x_per * $index ) + $svg_padding;
    //  Y is from the top.
    $y_pos = $svg_height - intval( $y_per * $views ) - $svg_padding;

    //  Add a point to the line.
    $polyline_points .= "{$x_pos},{$y_pos}\n";
}

echo &lt;&lt;&lt; SVG
&lt;svg xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 $svg_width $svg_height" class="chart"&gt;
    &lt;polyline
        fill="none"
        stroke="#F00"
        stroke-width="3"
        points="{$polyline_points}"/&gt;
&lt;/svg&gt;
SVG;
</code></pre>

<p>Suppose someone suggests stupidly simple sparklines suffer seriously so someone should supplement statistics several circles?</p>

<p>Using the same co-ordinates, we can place an SVG circle on top of the point. Give it a "title" attribute and you have a little bit of interactivity.</p>

<pre><code class="language-svg">&lt;circle cx="12" cy="48" r="5" fill="#0074D955"&gt;&lt;title&gt;4,707 Views&lt;/title&gt;&lt;/circle&gt;
</code></pre>

<p>Here's how it looks (view source to understand how it is constructed).</p>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 124" class="chart">
<polyline fill="none" stroke="#0074D9" stroke-width="3" points="12,48
83,84
154,79
226,90
297,79
369,65
440,78
512,80
583,88
654,12
726,56
797,92
869,93
940,97
1012,105
"></polyline>
<circle cx="12" cy="48" r="5" fill="#0074D955"><title>4,707
2025-09-01</title></circle><circle cx="83" cy="84" r="5" fill="#0074D955"><title>2,051
2025-09-02</title></circle><circle cx="154" cy="79" r="5" fill="#0074D955"><title>2,444
2025-09-03</title></circle><circle cx="226" cy="90" r="5" fill="#0074D955"><title>1,627
2025-09-04</title></circle><circle cx="297" cy="79" r="5" fill="#0074D955"><title>2,450
2025-09-05</title></circle><circle cx="369" cy="65" r="5" fill="#0074D955"><title>3,453
2025-09-06</title></circle><circle cx="440" cy="78" r="5" fill="#0074D955"><title>2,491
2025-09-07</title></circle><circle cx="512" cy="80" r="5" fill="#0074D955"><title>2,326
2025-09-08</title></circle><circle cx="583" cy="88" r="5" fill="#0074D955"><title>1,754
2025-09-09</title></circle><circle cx="654" cy="12" r="5" fill="#0074D955"><title>7,268
2025-09-10</title></circle><circle cx="726" cy="56" r="5" fill="#0074D955"><title>4,113
2025-09-11</title></circle><circle cx="797" cy="92" r="5" fill="#0074D955"><title>1,503
2025-09-12</title></circle><circle cx="869" cy="93" r="5" fill="#0074D955"><title>1,394
2025-09-13</title></circle><circle cx="940" cy="97" r="5" fill="#0074D955"><title>1,108
2025-09-14</title></circle><circle cx="1012" cy="105" r="5" fill="#0074D955"><title>533
2025-09-15</title></circle></svg>

<p>Hover over any of those little circles and you'll see some pop-up text giving you information about that datapoint.</p>

<p>…that's it! If you have an array of data points, you can easily create a graph with no graphing library, no plugins, no 3rd party dependencies. Just super simple SVG.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=63359&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/stupidly-simple-svg-sparklines/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Find blog posts with missing featured images - and missing alt text - without a plugin]]></title>
		<link>https://shkspr.mobi/blog/2026/05/find-blog-posts-with-missing-featured-images-and-missing-alt-text-without-a-plugin/</link>
					<comments>https://shkspr.mobi/blog/2026/05/find-blog-posts-with-missing-featured-images-and-missing-alt-text-without-a-plugin/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 11 May 2026 11:34:39 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[accessibility]]></category>
		<category><![CDATA[TILvember]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=63594</guid>

					<description><![CDATA[WordPress has the concept of &#34;Featured Images&#34;. They are the images which show up when you share a blog post on social media or, on some themes, as the &#34;hero&#34; image.  How can you quickly and easily find any posts which don&#039;t have a featured image?  For this, I use WP CLI - it allows you to run complex WordPress actions and queries using the command line.  After you have installed WP CLI you can…]]></description>
										<content:encoded><![CDATA[<p>WordPress has the concept of "Featured Images". They are the images which show up when you share a blog post on social media or, on some themes, as the "hero" image.</p>

<p>How can you quickly and easily find any posts which <em>don't</em> have a featured image?</p>

<p>For this, I use <a href="https://wp-cli.org/">WP CLI</a> - it allows you to run complex WordPress actions and queries using the command line.  After you have <a href="https://wp-cli.org/#installing">installed WP CLI</a> you can get started.</p>

<h2 id="missing-images"><a href="https://shkspr.mobi/blog/2026/05/find-blog-posts-with-missing-featured-images-and-missing-alt-text-without-a-plugin/#missing-images">Missing Images</a></h2>

<p>On the command line, run:</p>

<pre><code class="language-_">wp eval 'foreach(get_posts(array("post_type"=&gt;"post","post_status"=&gt;array("publish"),"posts_per_page"=&gt;-1,)) as $post){if(get_the_post_thumbnail($post)==""){$post_type_object=get_post_type_object($post-&gt;post_type);$link=admin_url(sprintf($post_type_object-&gt;_edit_link . "&amp;action=edit", $post-&gt;ID));echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n";}}'
</code></pre>

<p>Here's the code in a slightly more readable format:</p>

<pre><code class="language-php">foreach ( 
   get_posts( 
       array( "post_type"      =&gt; "post", 
              "post_status"    =&gt; array("publish"), 
              "posts_per_page" =&gt; -1,
       ) 
   ) as $post) { 
      if( get_the_post_thumbnail( $post)== "" ) { 
         $post_type_object = get_post_type_object( $post-&gt;post_type ); 
         $link = admin_url( sprintf( $post_type_object-&gt;_edit_link . "&amp;action=edit", $post-&gt;ID ) ) ;
         echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n";
      } 
}
</code></pre>

<p>That will print out:</p>

<pre><code class="language-_">2024-05-02 12:34:11 https://example.com/wp-admin/post.php?post=123&amp;action=edit "A post about sausages" 
2023-09-13 20:55:52 https://example.com/wp-admin/post.php?post=456&amp;action=edit "I like cheese"
2021-12-31 15:43:33 https://example.com/wp-admin/post.php?post=789&amp;action=edit "Touching computers"
</code></pre>

<p>You can then go and edit each of those posts to add a featured image.</p>

<h2 id="missing-alt-text"><a href="https://shkspr.mobi/blog/2026/05/find-blog-posts-with-missing-featured-images-and-missing-alt-text-without-a-plugin/#missing-alt-text">Missing Alt Text</a></h2>

<p>Adding alt text means that people who can't see images will still be able to understand what the picture represents. Here's another one-lines to find all featured images with missing alt text:</p>

<pre><code class="language-_">wp eval 'foreach (get_posts(array("post_type"=&gt;"post","post_status"=&gt;array("publish"),"posts_per_page" =&gt; -1,)) as $post){if(simplexml_load_string(get_the_post_thumbnail($post))["alt"]==""){$post_type_object=get_post_type_object($post-&gt;post_type);$link=admin_url(sprintf($post_type_object-&gt;_edit_link . "&amp;action=edit",$post-&gt;ID));echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n";}}'
</code></pre>

<p>And, in slightly more readable form:</p>

<pre><code class="language-php">foreach (
   get_posts( 
      array( "post_type"      =&gt; "post", 
             "post_status"    =&gt; array("publish"), 
             "posts_per_page" =&gt; -1,
           ) 
   ) as $post) { 
      if( simplexml_load_string( get_the_post_thumbnail( $post ) )["alt"] == "") { 
         $post_type_object = get_post_type_object( $post-&gt;post_type ); 
         $link = admin_url( sprintf( $post_type_object-&gt;_edit_link . "&amp;action=edit", $post-&gt;ID ) ) ;
         echo $post-&gt;post_date . " " . $link . " " . $post-&gt;post_title . "\n"; 
      } 
}
</code></pre>

<p>Again, that lists the datetime of the post, its edit link, and its title.</p>

<p>Now, if you'll excuse me, I have about 873 posts which need updating 🤯</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=63594&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/find-blog-posts-with-missing-featured-images-and-missing-alt-text-without-a-plugin/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[I've found just the right paper for my Bottom Hole problem]]></title>
		<link>https://shkspr.mobi/blog/2026/05/ive-found-just-the-right-paper-for-my-bottom-hole-problem/</link>
					<comments>https://shkspr.mobi/blog/2026/05/ive-found-just-the-right-paper-for-my-bottom-hole-problem/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 07 May 2026 11:34:54 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[comedy]]></category>
		<category><![CDATA[newspapers]]></category>
		<category><![CDATA[tv]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=71393</guid>

					<description><![CDATA[A few weeks ago, I went on a mad quest to find the newspaper used in 1995&#039;s Bottom Hole TV show.  During the episode, Eddie starts reading this newspaper:    Obviously, the &#34;Hammersmith Bugle&#34; is not a real paper and they never ran a headline &#34;No News Shocker&#34;. But judging from all the other shots, the prop is based on a real newspaper.    So I decided to rip off Dirty Feed&#039;s shtick and find out…]]></description>
										<content:encoded><![CDATA[<p>A few weeks ago, I went on a mad quest to find <a href="https://shkspr.mobi/blog/2026/03/finding-the-right-bottom-hole-paper/">the newspaper used in 1995's Bottom Hole TV show</a>.</p>

<p>During the episode, Eddie starts reading this newspaper:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/No-News-Shocker.webp" alt="Some pissed old fart reading a newspaper called &quot;The Hammersmith Bugle&quot; with the headline &quot;No news shocker...&quot;" width="720" height="544" class="aligncenter size-full wp-image-68986">

<p>Obviously, the "Hammersmith Bugle" is not a real paper and they never ran a headline "No News Shocker". But judging from all the other shots, the prop is based on a <em>real</em> newspaper.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/Seewaw.webp" alt="Two reprobates reading a newspaper." width="720" height="544" class="aligncenter size-full wp-image-68989">

<p>So I decided to <a href="https://www.dirtyfeed.org/tag/newspaper-props/">rip off Dirty Feed's shtick</a> and find out what was used to create the fake newspaper. The quest took me o'er hill and dale. Through the rough hinterlands of Hammersmith and into the nether regions of Wimbledon. By which I mean - I used lots of online archive sources.</p>

<p>And it <em>nearly</em> worked! I found all of the <em>internal</em> pages. I also found the back page:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/Cup-Tie-Chaos.webp" alt="Idiot in a pork pie hat reading a paper with the headline &quot;Cup tie chaos&quot;." width="720" height="544" class="aligncenter size-full wp-image-68987">

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/Cup-Tie-Paper.webp" alt="Scan of a newspaper with &quot;Cup tie chaos&quot; as a headline." width="720" class="aligncenter size-full wp-image-68990">

<p>That's from <a href="https://www.britishnewspaperarchive.co.uk/search/results/1994-11-03/1994-11-03?NewspaperTitle=Surrey%2BHerald&amp;IssueId=BL%2F0003604%2F19941103%2F&amp;County=Surrey%2C%20England">The Surrey Herald</a> - but that's a paper with <em>lots</em> of regional editions. None of which had the right headline.</p>

<p>So I emailed my (frankly asinine ) request to <a href="https://www.surreycc.gov.uk/culture-and-leisure/history-centre/researchers/guides/newspaper-back-issues">Surrey Museums</a>. They were polite, but unable to help. Their website gave a clue though - the location of the archives of the Surrey Herald:</p>

<blockquote><p>Surrey Herald: Chertsey, Addlestone and Byfleet edition (also Walton, Weybridge and Hersham edition Feb 1979 to 1999 at Elmbridge Museum)</p></blockquote>

<p>So I contacted the fine people at <a href="https://elmbridgemuseum.org.uk/">Elmbridge Museum</a> who were happy to rummage through their microfiche for me. I expect, much like Indiana Jones, the archivists had to knock down fake walls, find a mystic box containing the treasure, and then dodge various snakes and villains to retrieve the priceless artefact. Or they may have a well designed archival system which is a pleasure to use. I don't know.</p>

<p>Anyway! All of which is to say that they very kindly sent me a quick scan of the front page of Surrey Herald's Walton, Weybridge and Hersham edition from November 3rd 1994.</p>

<p>Here it is in all its glory!</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/05/Herald-1024.webp" alt="Front page of the newspaper." width="1024" height="1375" class="aligncenter size-full wp-image-71395">

<p>That's a <em>perfect</em> match for what's seen on screen:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/03/FA-Cup-Mix-up.webp" alt="High resolution clip of a newspaper." width="474" height="588" class="aligncenter size-full wp-image-69069">

<p>Hurrah! Another mystery solved thanks to <a href="https://elmbridgemuseum.org.uk/">publicly funded museums</a>!</p>

<h2 id="what-have-we-learned-today"><a href="https://shkspr.mobi/blog/2026/05/ive-found-just-the-right-paper-for-my-bottom-hole-problem/#what-have-we-learned-today">What have we learned today?</a></h2>

<ul>
<li>Archivists are lovely, generous, and helpful people.</li>
<li>Museums are brilliant.</li>
<li>Not everything in the world has been digitised.</li>
<li>There was <em>quite a lot</em> of news that day no matter what the drunken hacks at the Hammersmith Bugle say.</li>
<li>We do not know if centenarian Elsie Bartlett was aware that her photo featured in this seminal part of British comedy.</li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=71393&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/ive-found-just-the-right-paper-for-my-bottom-hole-problem/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[RSS Feeds Send Me More Traffic Than Google]]></title>
		<link>https://shkspr.mobi/blog/2026/05/rss-feeds-send-me-more-traffic-than-google/</link>
					<comments>https://shkspr.mobi/blog/2026/05/rss-feeds-send-me-more-traffic-than-google/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 05 May 2026 11:34:12 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[meta]]></category>
		<category><![CDATA[statistics]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70238</guid>

					<description><![CDATA[Yeah yeah, I know, data-point of 1.  I recently read Susam&#039;s blog post where they said that &#34;most of the traffic to my personal website still comes from web feeds&#34; - I wondered if that was true for my site.  I&#039;ve been writing this blog for a while. I&#039;ve never much bothered with &#34;aggressive&#34; SEO - I have a fairly semantic layout, all my reviews have metadata, and stuff like that - but I&#039;m not…]]></description>
										<content:encoded><![CDATA[<p>Yeah yeah, I know, data-point of 1.</p>

<p>I recently read <a href="https://susam.net/from-rss-to-atom.html">Susam's blog post</a> where they said that "most of the traffic to my personal website still comes from web feeds" - I wondered if that was true for my site.</p>

<p>I've been writing this blog for a while. I've never much bothered with "aggressive" <abbr title="Search Engine Optimisation">SEO</abbr> - I have a fairly <a href="https://shkspr.mobi/blog/2026/01/maximally-semantic-structure-for-a-blog-post/">semantic layout</a>, all my <a href="https://shkspr.mobi/blog/2023/01/restaurant-review-metadata/">reviews have metadata</a>, and stuff like that - but I'm not cramming in keywords, using AMP, or whatever other chickens Google requires to be sacrificed for a higher ranking. Nevertheless, I do OK.</p>

<p>Last year, I added a bit of <a href="https://shkspr.mobi/blog/2025/09/reasonably-accurate-privacy-conscious-cookieless-visitor-tracking-for-wordpress/">local-only, lightweight statistics-gathering</a> to my blog. I can see which sites people click on to reach mine. Google is right up the top, DuckDuckGo is surprisingly high, Bing is lucky to crack the top 20 on any day. Similarly, I can see <a href="https://shkspr.mobi/blog/2025/11/now-witness-the-power-of-this-fully-operational-fediverse/">how much traffic I get from the Fediverse</a> and BlueSky (Twitter has all but vanished).</p>

<p>A few weeks ago I added RSS and Newsletter tracking. These data are <em>very</em> lossy. If someone is subscribed to my RSS feed <em>and</em> opens a post <em>and</em> their client downloads a lazy-loaded image at the end of the post, I get a hit. For email it's broadly the same. If an email is opened and the tracker image is loaded, I get a hit (although <a href="https://gmail.googleblog.com/2013/12/images-now-showing.html">Gmail does obfuscate that somewhat</a>).</p>

<p>I'm not looking for super-accurate numbers (although I do block as many AI crawlers and bots as possible). I'm not creepily following people around the web nor am I trying to sell them anything. I just want a rough idea of where people find me.</p>

<p>Here are my blog's views for the last 28 days.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/05/page-views.webp" alt="Atom 13774. Google 10833. RSS 10419. DuckDuckGo 2302. Email 2123." width="553" height="395" class="aligncenter size-full wp-image-71208 no-border-radius">

<p>Some months I get a surge of hits from link aggregators like HN or Reddit. Sometimes I'm linked to from a popular site or <a href="https://shkspr.mobi/blog/citations">cited in academic work</a>. But most of the time I bumble along getting hits from here, there, and everywhere. Nevertheless, it's lovely to see so many people choosing to subscribe<sup id="fnref:rss"><a href="https://shkspr.mobi/blog/2026/05/rss-feeds-send-me-more-traffic-than-google/#fn:rss" class="footnote-ref" title="For historic reasons, I have separate Atom and RSS feeds. Perhaps I should consider merging them? But it doesn't take much effort to publish in two subtly different formats." role="doc-noteref">0</a></sup> (for free!) and astonishing that they provide more traffic than a major search engine.</p>

<p>Obviously, these are two <em>very</em> different types of traffic. People who are searching for a specific thing and stumble upon my blog are different from those who decide to like and subscribe.</p>

<p>But, yeah, about 25% of my traffic comes from people who have chosen to subscribe.</p>

<p>I'm just delighted that so many people read my random thoughts.</p>

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

<li id="fn:rss">
<p>For historic reasons, I have separate Atom and RSS feeds. Perhaps I should consider merging them? But it doesn't take much effort to publish in two subtly different formats.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/rss-feeds-send-me-more-traffic-than-google/#fnref:rss" 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=70238&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/rss-feeds-send-me-more-traffic-than-google/feed/</wfw:commentRss>
			<slash:comments>13</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>
</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>36</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Android now stops you sharing your location in photos]]></title>
		<link>https://shkspr.mobi/blog/2026/04/android-now-stops-you-sharing-your-location-in-photos/</link>
					<comments>https://shkspr.mobi/blog/2026/04/android-now-stops-you-sharing-your-location-in-photos/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 13 Apr 2026 11:34:48 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[geotagging]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[OpenBenches]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70143</guid>

					<description><![CDATA[My wife and I run OpenBenches. It&#039;s a niche little site which lets people share photos of memorial benches and their locations. Most modern phones embed a geolocation within the photo&#039;s metadata, so we use that information to put the photos on a map.  Google&#039;s Android has now broken that.  On the web, we used to use:  &#60;input type=&#34;file&#34; accept=&#34;image/jpeg&#34;&#62;   That opened the phone&#039;s photo picker…]]></description>
										<content:encoded><![CDATA[<p>My wife and I run <a href="https://openbenches.org">OpenBenches</a>. It's a niche little site which lets people share photos of memorial benches and their locations. Most modern phones embed a geolocation within the photo's metadata, so we use that information to put the photos on a map.</p>

<p>Google's Android has now broken that.</p>

<p>On the web, we used to use:</p>

<pre><code class="language-html">&lt;input type="file" accept="image/jpeg"&gt;
</code></pre>

<p>That opened the phone's photo picker and let the use upload a geotagged photo. But a while ago Google deliberately broke that.</p>

<p>Instead, we were <a href="https://issuetracker.google.com/issues/243294058#comment27">encourage to use the <em>file</em> picker</a>:</p>

<pre><code class="language-html">&lt;input type="file"&gt;
</code></pre>

<p>That opened the default file manager. This had the unfortunate side-effect of allowing the user to upload <em>any</em> file, rather than just photos. But it did allow the EXIF metadata through unmolested.  <a href="https://issuetracker.google.com/issues/428397711">Then Google broke that as well</a>.</p>

<p>Using a "Progressive Web App" doesn't work either.</p>

<p>So, can users transfer their photos via Bluetooth or QuickShare? No. <a href="https://issuetracker.google.com/issues/485307531">That's now broken as well</a>.</p>

<p>You can't even directly share via email without the location being stripped away.</p>

<p>Literally the <em>only</em> way to get a photo with geolocation intact is to plug in a USB cable, copy the photo to your computer, and then upload it via a desktop web browser?</p>

<h2 id="why"><a href="https://shkspr.mobi/blog/2026/04/android-now-stops-you-sharing-your-location-in-photos/#why">Why?!?!?</a></h2>

<p><del>Because Google run an anticompetitive monopoly on their dominant mobile operating system.</del></p>

<p>Privacy.</p>

<p>There's a worry that users don't know they're taking photos with geolocation enabled. If you post a cute picture of your kid / jewellery / pint then there's a risk that a ne’er-do-well could find your exact location.</p>

<p>Most social media services are sensible and strip the location automatically. If you try to send a geotagged photo to Facebook / Mastodon / BlueSky / WhatsApp / etc, they default to <em>not</em> showing the location. You can add it in manually if you want, but anyone downloading your photo won't see the geotag.</p>

<p>And, you know, I get it. Google doesn't want the headline "Stalkers found me, kidnapped my baby, and stole my wedding ring - how a little known Android feature puts you in danger!"</p>

<p>But it is just so <em>tiresome</em> that Google never consults their community. There was no advance notice of this change that I could find. Just a bunch of frustrated users in my inbox blaming me for breaking something.</p>

<p>I don't know what the answer is. Perhaps a pop up saying "This website wants to see the location of your photos. Yes / No / Always / Never"? People get tired of constant prompts and the wording will never be clear enough for most users.</p>

<p>It looks like the only option available will be to develop a native Android app (and an iOS one?!) with all the cost, effort, and admin that entails. Android apps have <a href="https://developer.android.com/training/data-storage/shared/media#location-media-captured">a special permission for accessing geolocation in images</a>.</p>

<p>If anyone has a <em>working</em> way to let Android web-browsers access the full geolocation EXIF metadata of photos uploaded on the web, please drop a comment in the box.</p>

<p>In the meantime, please leave a +1 on <a href="https://github.com/whatwg/html/issues/11724#issuecomment-4192228562">this HTML Spec comment</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70143&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/04/android-now-stops-you-sharing-your-location-in-photos/feed/</wfw:commentRss>
			<slash:comments>26</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Random File Format]]></title>
		<link>https://shkspr.mobi/blog/2026/04/random-file-format/</link>
					<comments>https://shkspr.mobi/blog/2026/04/random-file-format/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 01 Apr 2026 11:34:57 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[experiment]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=65027</guid>

					<description><![CDATA[This was an idea I had back in the days of Naptster.  At the turn of the century, it was common to listen to an &#34;acquired&#34; music file only to find it was missing a few seconds at the end due to a prematurely stopped download.  Some video formats would refuse to play at all if the moov atom at the end of the file was missing.  I wondered if it would be possible to make a file format which was…]]></description>
										<content:encoded><![CDATA[<p>This was an idea I had back in the days of Naptster.</p>

<p>At the turn of the century, it was common to listen to an "acquired" music file only to find it was missing a few seconds at the end due to a prematurely stopped download.  Some video formats would refuse to play at all if the <a href="https://www.cnwrecovery.com/manual/Fragmented3GPMP4Files.html"><code>moov</code> atom at the end of the file was missing</a>.</p>

<p>I wondered if it would be possible to make a file format which was close to impossible to read unless the <em>entire</em> file was intact. I don't mean including a checksum to detect download errors - I mean a layout which was <strong>intrinsically fragile</strong> to corruption.</p>

<p>While digging through an old backup CD, I found my original notes. I'm rather impressed at what neophyte-me had constructed.  My outline was:</p>

<ul>
<li>The file ends with a 32 bit pointer. This points to the location of the first information block.</li>
<li>The information block describes the length of the data block which follows it.</li>
<li>At the end of the data block is another 32 bit pointer. This points to the location of the next information block.</li>
<li>The start of the file may be a pointer, or it may be padded with random data.</li>
<li>There may be random data padded between the data blocks.</li>
</ul>

<p>This ensures that a file which has been only partially downloaded - whether truncated at the end or missing pieces elsewhere - cannot be successfully read.</p>

<p>Here's a worked example. Start at the end and follow the thread.</p>

<ol start="0">
<li>Random data.</li>
<li>Data block size is 2.</li>
<li>Data</li>
<li>Data</li>
<li>EOF.</li>
<li>Data block size is 1.</li>
<li>Data.</li>
<li>Go to location 1.</li>
<li>Random data.</li>
<li>Go to location 5.</li>
</ol>

<p>There are, of course, a few downsides to this idea.</p>

<p>Most prominently, it bloats file size. If the data block size was a constant 1MB, that would pad the size a negligible amount. But with variable data block size, it could increase it significantly. Random padding also increases the size.</p>

<p>If the block size is consistent and there's no random padding data, the files can be mostly reconstructed.</p>

<p>Depending on which parts of the file are missing, it may be possible to recover the majority of the file.</p>

<p>A location block size of 32 bits restricts the file-size to less than 4GB. A 64 bit pointer might be excessive or might be future-proof!</p>

<p>Highly structured files with predictable patterns, or text files, may be easy to recover large bits of information.</p>

<p>A malformed file could contain an infinite loop of pointers.</p>

<p>Perhaps a <a href="https://en.wikipedia.org/wiki/File_format#Magic_number">magic number</a> should be at the start (or end) of the file?</p>

<p>While reading the file is as simple as following the pointers, <em>constructing</em> the file is more complex, especially if blocks have variable lengths.</p>

<h2 id="code"><a href="https://shkspr.mobi/blog/2026/04/random-file-format/#code">Code</a></h2>

<p>Here's a trivial encoder. It reads a file in consistently sized chunks of 1,024 bytes. It shuffles them up and writes them to a new file. The last 4 bytes contain a pointer to the first block, which says the data length is 1,024. After that, there is a 4 byte pointer to the next block location.</p>

<pre><code class="language-python">import random

#   Size of data, headers, and pointers.
data_length = 1024
header_length  = 4
pointer_length = 4

#   Read the file into a data structure.
original_blocks = list()
with open( "test.jpg", "rb") as file:
    for data in iter( lambda: file.read( data_length ), b"" ):
        #   Add padding if length is less than the desired length.
        padding = data_length - len( data )
        data += b"\0" * padding
        original_blocks.append( data )

#   How many blocks are there?
original_length = len( original_blocks )

#   Create a random order of blocks.
order = list( range( 0, original_length ) )
random.shuffle( order )

#   Where is the start of the file?
first_block_index = order.index( 0 )
first_block_pointer = first_block_index * ( header_length + data_length + pointer_length )

#   Loop through the order and write to a new file.
i = 0
#   Open as binary file to add the pointers correctly.
with open( "output.rff", "wb" ) as output:
    while i &lt; original_length:
        #   Where are we?
        current_block = i
        current_block_value = order[i]
        #   Write length of data in little-endian 32 bytes.
        output.write( data_length.to_bytes( header_length, "little") )
        #   Write data
        output.write( original_blocks[ current_block_value ] )
        i = i+1
        #   Last block. Write an EOF header.
        if ( current_block_value + 1 &gt;= original_length ):
            eof = 4294967295
            output.write( eof.to_bytes( header_length, "little") )
        else:
            next_block = order.index( current_block_value + 1 )
            #   Write pointer to next block
            next_block_location = next_block * ( header_length + data_length + pointer_length )
            output.write( next_block_location.to_bytes( pointer_length, "little" ) )
    #   At the end of the file, write the pointer to block 0.
    output.write( first_block_pointer.to_bytes( pointer_length, "little" ) )
</code></pre>

<p>And here is a similarly trivial decoder. It reads the last 32 bits, moves to that location, reads the block size, reads the data and writes it to a new file, then reads the next pointer.</p>

<pre><code class="language-python">import os
#   Size of data, headers, and pointers.
header_length  = 4
pointer_length = 4
#   File name to write to.
decoded_file = "decoded.bin"

#   Create an empty file.
with open( decoded_file, "w") as file:
    pass

#   Function to loop through the blocks.
def read_block( position, i ):
    #   Move to the position in the file.
    input_file.seek( position, 0 )
    #   Read the data length header.
    data_length = int.from_bytes( input_file.read( header_length ), "little" )
    #   Move to the data block.
    input_file.seek( position + header_length, 0 )
    #   Read the data.
    data = input_file.read( data_length )
    #   Read the pointer header.
    next_position = int.from_bytes( input_file.read( pointer_length ), "little" )
    #   If this is the final block, it may have null padding. Remove it.
    if ( next_position == 4294967295 ) :
        data = data.rstrip(b"\0")
    #   Append the data to the decoded file.
    with open( decoded_file, "ab" ) as file:
        file.write( data )
    #   If this is the final block, finish searching.
    if ( next_position == 4294967295 ) :
         print("File decoded.")
    else:
        #   Move to the next position.
        read_block( next_position, i+1 )

#   Open the file as binary.
input_file = open( "output.rff", "rb" )

#   Read the last 4 bytes.
input_file.seek( -4, 2 )

#   Get position of first block
first_block = int.from_bytes( input_file.read(), "little" )

#   Start reading the file.
seek_to = first_block
read_block( seek_to, 0 )
</code></pre>

<p>As I said, these are both trivial. They are a bit buggy and contain some hardcoded assumptions.</p>

<p>Here are two files encoded as "RFF" - Random File Format - <a href="https://shkspr.mobi/blog/wp-content/uploads/2026/03/output.jpg.rff">an image</a> by Maria Sibylla Merian, and the <a href="https://shkspr.mobi/blog/wp-content/uploads/2026/03/output.txt.rff">text of Romeo and Juliet</a>.</p>

<p>Have fun decoding them!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=65027&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/04/random-file-format/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[The Unintended Consequences of Gamification]]></title>
		<link>https://shkspr.mobi/blog/2012/10/the-unintended-consequences-of-gamification/</link>
					<comments>https://shkspr.mobi/blog/2012/10/the-unintended-consequences-of-gamification/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 01 Oct 2012 11:34:05 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[gaming]]></category>
		<category><![CDATA[necropost]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=34146</guid>

					<description><![CDATA[This is a necropost - resurrected from the now defunct blog of a previous employer. Sadly, most of the screenshots have fallen down the memory hole. So use your imagination. We&#039;d launched Drive To Improve which put a &#34;blackbox&#34; in drivers&#039; cars and gamified their safe driving.  I’ve recently taken part in the DriveToImprove Beta. My car now has a small device installed in it, which measures my d…]]></description>
										<content:encoded><![CDATA[<p><ins datetime="2026-05-09T19:28:51+00:00">This is a necropost - resurrected from the <a href="https://web.archive.org/web/20121014115914/http://thelab.o2.com/2012/10/the-unintended-consequences-of-gamification/">now defunct blog of a previous employer</a>. Sadly, most of the screenshots have fallen down the memory hole. So use your imagination. We'd launched <a href="https://inform.tmforum.org/research-and-analysis/case-studies/case-study-o2-drives-a-new-insurance-experience-for-customers">Drive To Improve</a> which put a "blackbox" in drivers' cars and gamified their safe driving.</ins></p>

<p>I’ve recently taken part in the <a href="https://web.archive.org/web/20121014115914/http://drivetoimprove.co.uk/">DriveToImprove Beta</a>. My car now has a small device installed in it, which measures my driving. It reports back to me my location, whether I was speeding, and if I’m braking or accelerating too harshly. It also gives me a great little dashboard showing how well I’m doing and how I compare to others.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2012/10/dti-header.webp" alt="Dashboard showing various driving scores." width="1200" height="575" class="aligncenter size-full wp-image-71541">

<p>Bringing “high scores” to real life is part of a trend known as “<a href="http://en.wikipedia.org/wiki/Gamification">gamification</a>“.</p>

<p>DriveToImprove has the usual aspects of modern <a href="https://web.archive.org/web/20121014115914/http://pewinternet.org/Reports/2012/Future-of-Gamification/Main-Findings/Section-12.aspx">gamification</a> – badges, a leaderboard, and the ability to track your progress.</p>

<p>As I was driving home one day last week, a child ran out in front of my car. I had only a split second to react – slam on the brakes and risk losing points for “Harsh Braking” or continue on, risk hitting the child, but maintain my perfect score…</p>

<p>It’s a real dilemma – safety vs score.</p>

<p>Of course, <em>no one</em> would think like that, would they? I certainly didn’t!</p>

<p>But gaming incentives have a funny effect on our brain. <a href="https://web.archive.org/web/20121014115914/https://class.coursera.org/gamification-2012-001/lecture/36">Games are fun – and that makes them highly emotionally manipulative</a>.</p>

<p>That use of scores, rewards, and fun can manipulate us in all sorts of <strong>negative</strong> ways. Games can encourage us to <a href="http://www.scmp.com/comment/blogs/article/1040401/gamification-hatred-new-kill-japs-online-game">hate</a>, to <a href="https://web.archive.org/web/20121014115914/http://thegloss.com/beauty/hunger-games-my-struggle-with-anorexia/">harm our bodies</a>, to <a href="http://gamification-research.org/2011/05/richard-bartle-on-gamification-too-much-of-a-good-thing/">join a cult</a>, it can cause you to <a href="http://yukaichou.com/gamification-research/farmville-game-mechanics-winning-addicting/">annoy your friends</a> – in some extreme cases, the pleasure associated with playing a game can take over someone’s life until they <a href="https://web.archive.org/web/20121014115914/http://www.computerandvideogames.com/358603/man-dies-after-playing-diablo-iii-for-40-hours/">literally play themselves to death</a>.</p>

<p>So, when designing systems which utilise gamification, we have to be aware that the human brain is susceptible to all sorts of tricks – and we have to be really careful when we subvert them.</p>

<p>We know from feedback on our community that <a href="https://web.archive.org/web/20121014115914/http://community.drivetoimprove.co.uk/t5/Feedback-and-Discussions/Harsh-acceleration-on-roundabouts/m-p/1378#U1378">sometimes rapid acceleration is necessary</a>. So is it always a good idea to penalise users for it?</p>

<p>Although we work hard to make sure that the game aspect of the products we create never take priority over safety, it’s impossible to predict what effect our stimulating of the brain’s pleasure centres will have. After all, <a href="https://web.archive.org/web/20121014115914/http://csdl.ics.hawaii.edu/techreports/11-05/11-05.pdf">earning rewards in a game can have the same effect on the brain as cocaine</a>!</p>

<p>What’s great about the test-and-learn approach we take at The Lab is that it gives us time to see the consequences of our developments. We can remain focussed on adding value to our applications, while remaining aware of any unintended side-effects.</p>

<p>I found this video from Eran May-raz and Daniel Lazo a startling and amusing look at what may happen if we let gamification run away with itself.</p>

<iframe title="Sight" src="https://player.vimeo.com/video/46304267?dnt=1&amp;app_id=122963" width="620" height="349" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=34146&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2012/10/the-unintended-consequences-of-gamification/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
