<?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/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Tue, 19 May 2026 09:55:27 +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[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>4</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>7</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[[RSS Club] Let's meet up AFK]]></title>
		<link>https://shkspr.mobi/blog/2026/05/rss-club-lets-meet-up-afk/</link>
					<comments>https://shkspr.mobi/blog/2026/05/rss-club-lets-meet-up-afk/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 20 May 2026 11:34:04 +0000</pubDate>
				<category><![CDATA[[RSS Club]]]></category>
		<category><![CDATA[RSS Club]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=71519</guid>

					<description><![CDATA[Shhhh! This post is only available to RSS subscribers like you 😊  My wife and I are preparing for a big Interrail journey through Europe. Whenever we go on holiday, we like to meet up with friendly locals to have a drink and chat. We did this on our last journey and it was great.  So, if you&#039;re a member of RSS club and fancy showing some tourists a cool bar, awesome restaurant (with vegan op…]]></description>
										<content:encoded><![CDATA[<p><mark><em>Shhhh!</em> This post is only available to RSS subscribers like you</mark> 😊</p>

<p>My wife and I are preparing for a big Interrail journey through Europe. Whenever we go on holiday, we like to meet up with friendly locals to have a drink and chat. <a href="https://shkspr.mobi/blog/2025/06/meeting-my-fedifriends-afk/">We did this on our last journey and it was great</a>.</p>

<p>So, if you're a member of RSS club and fancy showing some tourists a cool bar, awesome restaurant (with vegan options), local tech conference, or nifty museum - please <a href="https://edent.tel/">get in touch</a>.</p>

<p>Our exact dates aren't finalised yet, but from now until the beginning of July, we'll be taking roughly this route:</p>

<ul>
<li>🇩🇪  Hamburg →</li>
<li>🇩🇰  Copenhagen →</li>
<li>🇸🇪  Gothenburg →</li>
<li>🇳🇴  Oslo →</li>
<li>🇸🇪  Stockholm →</li>
<li>🇫🇮  Helsinki →</li>
<li>🇪🇪  Tallinn →</li>
<li>🇱🇻  Riga →</li>
<li>🇱🇹  Vilnius →</li>
<li>🇵🇱  Warsaw →</li>
<li>🇩🇪  Berlin → Munich →</li>
<li>🇮🇹  Verona → Milan →</li>
<li>🇨🇭  Basel →</li>
<li>🇫🇷  Paris</li>
</ul>

<p>If you're in one of those cities and fancy a beer &amp; veggie burger, please give us a shout. We won't be able to meet everyone as we do have some existing plans and tight connections but, as they say, it's nice to <a href="https://www.youtube.com/watch?v=JhVRzh4_j50">go where everybody knows your name</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=71519&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/rss-club-lets-meet-up-afk/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Book Review: Terrible Worlds: Destinations by Adrian Tchaikovsky ★★★★★]]></title>
		<link>https://shkspr.mobi/blog/2026/05/book-review-terrible-worlds-destinations-by-adrian-tchaikovsky/</link>
					<comments>https://shkspr.mobi/blog/2026/05/book-review-terrible-worlds-destinations-by-adrian-tchaikovsky/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 19 May 2026 11:34:17 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Book Review]]></category>
		<category><![CDATA[NetGalley]]></category>
		<category><![CDATA[Sci Fi]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=71710</guid>

					<description><![CDATA[What&#039;s better than one Adrian Tchaikovsky novella? Three Adrian Tchaikovsky novellæ! Or is it &#34;novellii&#34;? Either way, a delightful triptych of stories on a common theme. On the surface, they&#039;re about travelling to a new destination (Space! The Future! For-Copyright-Reasons Not Narnia!)  Except, deep down, they&#039;re about loneliness. No matter how far or fast we run, no matter where or when we go, …]]></description>
										<content:encoded><![CDATA[<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/05/tw-destinations-470.webp" alt="Book cover." width="235" height="369" class="alignleft size-full wp-image-71711">

<p>What's better than one Adrian Tchaikovsky novella? <em>Three</em> Adrian Tchaikovsky novellæ! Or is it "novellii"? Either way, a delightful triptych of stories on a common theme. On the surface, they're about travelling to a new destination (Space! The Future! For-Copyright-Reasons Not Narnia!)</p>

<p>Except, deep down, they're about loneliness. No matter how far or fast we run, no matter where or when we go, we can't outrun ourselves. When you enter the void, sometimes the void enters you.</p>

<p>There's also the constant theme about the hunter becoming the hunted. All three of the stories reminded me a bit of <a href="https://shkspr.mobi/blog/2022/04/book-review-piranesi-by-susanna-clarke/">Piranesi by Susanna Clarke</a> - in that I was never quite sure if the characters were simply delusional and waging war on an enemy of their own making.</p>

<p>It brims with a pathos which I find rare in modern science fiction. That's offset with the perfectly placed <em>British</em> humour within it. Yes, there's a touch of the Weir/Scalzi "Only I, a nerdy guy, can save the universe in a self-knowing way" - but those authors aren't brave enough to mention Reading town centre or have their hero hail from Stevenage. Whereas Tchaikovsky knows what's up with the Furries.</p>

<p>An excellent collection of tales.</p>

<p>Many thanks to NetGalley for the review copy. The book is available to buy now.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=71710&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/book-review-terrible-worlds-destinations-by-adrian-tchaikovsky/feed/</wfw:commentRss>
			<slash:comments>1</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>8</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[UK Government Kicks Out Palantir]]></title>
		<link>https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/</link>
					<comments>https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 15 May 2026 05:34:03 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=71169</guid>

					<description><![CDATA[The UK Government, for all its faults, is pretty good at publishing contracts it has awarded. That&#039;s why I get depressed when I see rage-bait nonsense about how companies have been award &#34;Top Secret&#34; deals.  Right now you can go to https://www.contractsfinder.service.gov.uk and search for whichever bête noire has you riled up. You might want to argue that the company is corrupt, incompetent, or …]]></description>
										<content:encoded><![CDATA[<p>The UK Government, for all its faults, is pretty good at publishing contracts it has awarded. That's why I get depressed when I see rage-bait nonsense about how companies have been award "Top Secret" deals.</p>

<p>Right now you can go to <a href="https://www.contractsfinder.service.gov.uk">https://www.contractsfinder.service.gov.uk</a> and search for whichever <i lang="fr">bête noire</i> has you riled up. You might want to argue that the company is corrupt, incompetent, or overpriced - but you can't argue that its contract is secret. There's no conspiracy. There's no secrecy. There's not even "beware of the leopard" shenanigans. It's all out in the open<sup id="fnref:except"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:except" class="footnote-ref" title="Yes, there occasionally delays and some things are redacted either for privacy, security, or confidentiality. But, in the main, if the Government has spent money on it, it'll be published somewhere." role="doc-noteref">0</a></sup>.</p>

<p>The Government says who it paying money to.</p>

<p>But, of course, there are some things the Government <em>can't</em> say. It's rare for them to publicly disagree with a supplier, or call out how crappy they were. They need to maintain cordial relations with people<sup id="fnref:cathartic"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:cathartic" class="footnote-ref" title="Yes, I know it would cathartic to have a YouTube Shocked Face &quot;Government SLAMS woeful supplier!!&quot; but the long-term consequences make it unlikely." role="doc-noteref">1</a></sup>. They don't want to scare off new suppliers who can't risk being publicly humiliated.  When contracts are cancelled or ended, it is usually done quietly.</p>

<p>So you need to learn to read between the lines.</p>

<p>Let's take this excellent blog post from the Ministry of Housing Communities and Local Government<sup id="fnref:mchlgchm"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:mchlgchm" class="footnote-ref" title="MHCLG is literally the worst acronym in a sea of unpronounceable alphabetti spaghetti. At least MOJ can be pronounced &quot;Modge&quot;!" role="doc-noteref">2</a></sup></p>

<p>"<a href="https://mhclgdigital.blog.gov.uk/2026/04/09/from-emergency-to-sustainability-creating-share-homes-for-ukraine-data/">From emergency to sustainability: creating Share Homes for Ukraine data</a>".</p>

<p>It's exactly the sort of blog post that some Civil Servants excel at writing. It clearly sets out how an ambitious and technically challenging project was delivered, why it is important, and who it benefits.</p>

<p>The blog post describes how the team…</p>

<blockquote><p>exited our contract with our supplier.</p></blockquote>

<p>And that:</p>

<blockquote><p>Moving to this in-house model is already saving MHCLG millions of pounds a year in running costs.</p></blockquote>

<p>They show user feedback for their new system saying:</p>

<blockquote><p>It’s easier to navigate than the previous system</p></blockquote>

<p>Of course, what they don't say is <em>who</em> supplied the previous system which was so costly and hard to use.</p>

<p>It was, of course, Palantir.</p>

<p>The <a href="https://www.contractsfinder.service.gov.uk/notice/b89e126f-8666-43d6-99b0-4e6a83a0c0a5">original contract (CPD4124104)</a> wasn't secret - although it was mired in <a href="https://www.ft.com/content/49de4d4d-5ac7-4f86-ac9e-17785be0aad9?syn-25a6b1a6=1">some controversy</a> as an urgent exemption to normal procurement rules<sup id="fnref:boring"><a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fn:boring" class="footnote-ref" title="My boring centrist dad position is that sometimes it makes sense to buy off-the-shelf in an emergency. If you find yourself abandoned after a night out, you order a taxi - you don't take up driving…" role="doc-noteref">3</a></sup>.</p>

<p>In 2023, the <a href="https://www.nao.org.uk/press-releases/investigation-into-homes-for-ukraine/">National Audit Office reported on the scheme</a> - including Palanitr's software.  They said:</p>

<blockquote><p>The initial arrangement was put in place to help get the scheme up and running quickly. Consequently, the system did not undergo the usual research and testing that would be involved for the roll-out of a new digital system. There were initial issues such as the way it presented duplicated application data received from Home Office systems, and confusion from local authorities as to how to engage with the main data system.</p></blockquote>

<p>How bad was Palantir's software? I've sent in a <a href="https://www.whatdotheyknow.com/request/usability_and_other_feedback_fro">Freedom of Information request to find out</a>. But we can tell that it was bad enough to convince MHCLG to rewrite it themselves.</p>

<p>A lean Civil Service may not have the in-house capability to rapidly create a new service. But, as their blog post shows, when given suitable resources Civil Servants can often <em>outperform</em> the private sector. More importantly, the new software is under the Ministry's direct control. This <a href="https://github.com/communitiesuk/ukraine-sponsor-resettlement">open source</a> code is a triumph for sovereign technology.</p>

<p>MHCLG have shown the door to Palantir. They've built something better, easier to use, and cheaper.</p>

<p>I don't want to oversell this as the first victory in the war against this <a href="https://www.bbc.co.uk/news/articles/c4gjkj7975po">abominable company</a> - but I hope where MHCLG leads, others will follow.</p>

<hr>

<p>You can <a href="https://www.bbc.co.uk/news/articles/c2l2j1lxdk5o">read more about this story on BBC News</a>.</p>

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

<li id="fn:except">
<p>Yes, there occasionally delays and some things are redacted either for privacy, security, or confidentiality. But, in the main, if the Government has spent money on it, it'll be published somewhere.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:except" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:cathartic">
<p>Yes, I know it would cathartic to have a <a href="https://www.ign.com/articles/youtubes-infamous-shocked-face-thumbnails-could-be-on-the-way-out">YouTube Shocked Face</a> "Government SLAMS woeful supplier!!" but the long-term consequences make it unlikely.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:cathartic" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:mchlgchm">
<p>MHCLG is literally the worst acronym in a sea of unpronounceable alphabetti spaghetti. At least MOJ can be pronounced "Modge"!&nbsp;<a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:mchlgchm" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:boring">
<p>My boring <a href="https://inews.co.uk/news/politics/centrist-dads-introducing-new-bugbear-online-corbynites-92779">centrist dad</a> position is that sometimes it makes sense to buy off-the-shelf in an emergency. If you find yourself abandoned after a night out, you order a taxi - you don't take up driving lessons.&nbsp;<a href="https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/#fnref:boring" 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=71169&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/uk-government-kicks-out-palantir/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<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>10</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>2</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[[RSS Club] A Sneak Preview of Upcoming Posts]]></title>
		<link>https://shkspr.mobi/blog/2026/05/rss-club-a-sneak-preview-of-upcoming-posts/</link>
					<comments>https://shkspr.mobi/blog/2026/05/rss-club-a-sneak-preview-of-upcoming-posts/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 10 May 2026 11:34:38 +0000</pubDate>
				<category><![CDATA[[RSS Club]]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[RSS Club]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=71376</guid>

					<description><![CDATA[Psssst! This top secret post is only available to RSS subscribers!  As a little thank-you for being a member of RSS Club I thought I&#039;d show you some trailers for upcoming blog posts.  I use the brilliant Editorial Calendar Plugin to organise all my scheduled blog posts. Here&#039;s what you can expect over the next month:    I tend to write in bursts - rather than once per day - and then spread the…]]></description>
										<content:encoded><![CDATA[<p><mark><em>Psssst!</em> This <strong>top secret</strong> post is only available to RSS subscribers!</mark></p>

<p>As a little thank-you for being a member of <a href="https://daverupert.com/rss-club/">RSS Club</a> I thought I'd show you some trailers for upcoming blog posts.</p>

<p>I use the brilliant <a href="https://editorialcalendarwp.com/">Editorial Calendar Plugin</a> to organise all my scheduled blog posts. Here's what you can expect over the next month:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/05/calendar.webp" alt="List of blog posts in a calendar layout. They are 
Put an AV test at the start of your slides. Stupidly Simple SVG Sparklines. Find blog posts with missing featured images - and missing alt text - without a plugin. This blog is written in en-GB. Game Review: Lovers In A Dangerous Spacetime. Death to px, long live ch!. Which age-gates should be skill-gates and vice-versa?. PHP - simple way to send HTTP headers before a script ends. Are Index Funds a Socialist Plot to Destroy America?. The UK Government's Low Value Purchase System is a Waste of Time. Whale Fall. Using FourSquare's API to post location checkins to social media. Virgin Media Hub 5 API. There's still no point in gigabit broadband." width="1609" height="835" class="aligncenter size-full wp-image-71378">

<p>I tend to write in bursts - rather than once per day - and then spread the posts out. As I'm going on a long break soon, I want to make sure there are plenty of posts in the queue.  There are also a bunch of posts scheduled over the next few years on specific dates.</p>

<p>Of course, if I unexpectedly die, I guess they be <em>post</em>humous…</p>

<p>I'm also working on what will be (I hope) a reasonably big political story. I'm under embargo until my media partner publishes it - but I hope it'll go live in the early hours of Tuesday. Stay tuned 😊</p>

<p>If there's something you'd like to see me write about, please <a href="https://edent.tel/">drop me a comment via your favourite method</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=71376&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/rss-club-a-sneak-preview-of-upcoming-posts/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Book Review: The Names by Florence Knapp ★★⯪☆☆]]></title>
		<link>https://shkspr.mobi/blog/2026/05/book-review-the-names-by-florence-knapp/</link>
					<comments>https://shkspr.mobi/blog/2026/05/book-review-the-names-by-florence-knapp/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 09 May 2026 11:34:20 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Book Club]]></category>
		<category><![CDATA[Book Review]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70668</guid>

					<description><![CDATA[This has an excellent narrative structure, some beautiful prose, and I just didn&#039;t enjoy it.  The story is Sliding Doors meets Same Time Next Year mixed with a distressing amount of domestic violence.  A mother faces a difficult choice. Should she name her child after her abusive and violent husband? In one strand she does, in another she doesn&#039;t, and in the third she makes a compromise. We…]]></description>
										<content:encoded><![CDATA[<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/the-names-7.jpg" alt="Book cover featuring a man with three shadows." width="180" height="276" class="alignleft size-full wp-image-70669">

<p>This has an excellent narrative structure, some beautiful prose, and I just didn't enjoy it.</p>

<p>The story is <a href="https://en.wikipedia.org/wiki/Sliding_Doors">Sliding Doors</a> meets <a href="https://en.wikipedia.org/wiki/Same_Time,_Next_Year_(play)">Same Time Next Year</a> mixed with a distressing amount of domestic violence.</p>

<p>A mother faces a difficult choice. Should she name her child after her abusive and violent husband? In one strand she does, in another she doesn't, and in the third she makes a compromise. We rejoin the story every few years to see how our protagonists are progressing.</p>

<p>It mostly works and pushes us to consider how much the path of our life is influenced by factors outside of our control.</p>

<p>I have a real difficulty with books about violence. All of the characters are unsympathetic - trapped by tyrant but also trapped by their own inaction. I also struggled with how pedestrian and limited it was. In a world where you can read anything, why would you choose to spy on your horrible neighbours?  Like a tawdry soap-opera it offered nothing more than misery and heartbreak. Fine if you need that sort of substitute empathy, but it left me feeling grubby and unsatisfied.</p>

<p>To be fair, the characters in the book address this:</p>

<blockquote><p>‘Why read them if they make you feel bad?’</p>

<p>‘Because I’m hoping one of them might feel like me,’</p></blockquote>

<p>It isn't a <em>bad</em> book - although it does veer into cliché a little too often - and the structure is interesting enough. But I found its subject matter too distressing to be enjoyable,</p>

<h2 id="book-club-discussion"><a href="https://shkspr.mobi/blog/2026/05/book-review-the-names-by-florence-knapp/#book-club-discussion">Book Club Discussion</a></h2>

<p>This isn't the sort of book I'd normally pick up - but it was chosen by the book club I attend.  The majority of readers rated it higher than I did. Here are some of the things we discussed.</p>

<p>The central message sees to be that, no matter how hard you try, the tragedy which infects your life can never be escaped. I found that depressing and disempowering. The domestic dreariness was stifling and just left me irritated with the passivity of the characters.</p>

<p>The evil father is an arsehole - but a <em>one-dimensional</em> arsehole. I get that there's a risk to humanising an antagonist, but other than a brief mention of his back-story there's nothing about him. I didn't want a <em>justification</em> for his actions, but he felt like a cartoon villain.</p>

<p>Even when one character gains a moment of happiness, it is offset by another's misery. No matter which path is chosen, someone always ends up broken.</p>

<p>Are we "destined" to meet the same people, no matter what path we take?</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70668&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/book-review-the-names-by-florence-knapp/feed/</wfw:commentRss>
			<slash:comments>0</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>14</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[[RSS Club] Where are you from?]]></title>
		<link>https://shkspr.mobi/blog/2026/05/rss-club-where-are-you-from/</link>
					<comments>https://shkspr.mobi/blog/2026/05/rss-club-where-are-you-from/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 04 May 2026 11:34:40 +0000</pubDate>
				<category><![CDATA[[RSS Club]]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[RSS Club]]></category>
		<category><![CDATA[statistics]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=71303</guid>

					<description><![CDATA[Psssst! This top secret post is only available to RSS subscribers!  A little while ago I added some locally hosted, privacy first stats to my blog. Using an offline GeoIP service I can get a very rough idea of where visitors are from.  It doesn&#039;t deal with people using a VPN, or their mobile roaming to a different country, or rapid changes in IP allocation - but it&#039;s good enough for my purposes.  …]]></description>
										<content:encoded><![CDATA[<p><mark><em>Psssst!</em> This <strong>top secret</strong> post is only available to RSS subscribers!</mark></p>

<p>A little while ago I added some <a href="https://shkspr.mobi/blog/2025/09/reasonably-accurate-privacy-conscious-cookieless-visitor-tracking-for-wordpress/">locally hosted, privacy first stats</a> to my blog. Using an <a href="https://mailfud.org/geoip-legacy/">offline GeoIP service</a> I can get a <em>very</em> rough idea of where visitors are from.</p>

<p>It doesn't deal with people using a VPN, or their mobile roaming to a different country, or rapid changes in IP allocation - but it's good enough for my purposes.</p>

<p>Here's a quick table showing the vague distribution of RSS Club members.</p>

<table>
<thead>
<tr>
  <th align="right"><strong>Country</strong></th>
  <th align="left"><strong>Flag</strong></th>
  <th align="right"><strong>Total Views</strong></th>
  <th align="right"><strong>Percentage</strong></th>
</tr>
</thead>
<tbody>
<tr>
  <td align="right">US</td>
  <td align="left">🇺🇸</td>
  <td align="right">6,242</td>
  <td align="right">24.1%</td>
</tr>
<tr>
  <td align="right">GB</td>
  <td align="left">🇬🇧</td>
  <td align="right">5,764</td>
  <td align="right">22.2%</td>
</tr>
<tr>
  <td align="right">DE</td>
  <td align="left">🇩🇪</td>
  <td align="right">1,947</td>
  <td align="right">7.5%</td>
</tr>
<tr>
  <td align="right">NL</td>
  <td align="left">🇳🇱</td>
  <td align="right">1,669</td>
  <td align="right">6.4%</td>
</tr>
<tr>
  <td align="right">CN</td>
  <td align="left">🇨🇳</td>
  <td align="right">1,027</td>
  <td align="right">4.0%</td>
</tr>
<tr>
  <td align="right">HK</td>
  <td align="left">🇭🇰</td>
  <td align="right">909</td>
  <td align="right">3.5%</td>
</tr>
<tr>
  <td align="right">AU</td>
  <td align="left">🇦🇺</td>
  <td align="right">770</td>
  <td align="right">3.0%</td>
</tr>
<tr>
  <td align="right">CA</td>
  <td align="left">🇨🇦</td>
  <td align="right">691</td>
  <td align="right">2.7%</td>
</tr>
<tr>
  <td align="right">FR</td>
  <td align="left">🇫🇷</td>
  <td align="right">605</td>
  <td align="right">2.3%</td>
</tr>
<tr>
  <td align="right">SE</td>
  <td align="left">🇸🇪</td>
  <td align="right">589</td>
  <td align="right">2.3%</td>
</tr>
<tr>
  <td align="right">JP</td>
  <td align="left">🇯🇵</td>
  <td align="right">442</td>
  <td align="right">1.7%</td>
</tr>
<tr>
  <td align="right">FI</td>
  <td align="left">🇫🇮</td>
  <td align="right">405</td>
  <td align="right">1.6%</td>
</tr>
<tr>
  <td align="right">CH</td>
  <td align="left">🇨🇭</td>
  <td align="right">395</td>
  <td align="right">1.5%</td>
</tr>
<tr>
  <td align="right">BR</td>
  <td align="left">🇧🇷</td>
  <td align="right">392</td>
  <td align="right">1.5%</td>
</tr>
<tr>
  <td align="right">ES</td>
  <td align="left">🇪🇸</td>
  <td align="right">345</td>
  <td align="right">1.3%</td>
</tr>
<tr>
  <td align="right">IT</td>
  <td align="left">🇮🇹</td>
  <td align="right">324</td>
  <td align="right">1.3%</td>
</tr>
<tr>
  <td align="right">PT</td>
  <td align="left">🇵🇹</td>
  <td align="right">285</td>
  <td align="right">1.1%</td>
</tr>
<tr>
  <td align="right">PL</td>
  <td align="left">🇵🇱</td>
  <td align="right">272</td>
  <td align="right">1.0%</td>
</tr>
<tr>
  <td align="right">BE</td>
  <td align="left">🇧🇪</td>
  <td align="right">249</td>
  <td align="right">1.0%</td>
</tr>
<tr>
  <td align="right">IN</td>
  <td align="left">🇮🇳</td>
  <td align="right">198</td>
  <td align="right">0.8%</td>
</tr>
<tr>
  <td align="right">CZ</td>
  <td align="left">🇨🇿</td>
  <td align="right">153</td>
  <td align="right">0.6%</td>
</tr>
<tr>
  <td align="right">TR</td>
  <td align="left">🇹🇷</td>
  <td align="right">134</td>
  <td align="right">0.5%</td>
</tr>
<tr>
  <td align="right">IE</td>
  <td align="left">🇮🇪</td>
  <td align="right">126</td>
  <td align="right">0.5%</td>
</tr>
<tr>
  <td align="right">BG</td>
  <td align="left">🇧🇬</td>
  <td align="right">121</td>
  <td align="right">0.5%</td>
</tr>
<tr>
  <td align="right">TW</td>
  <td align="left">🇹🇼</td>
  <td align="right">114</td>
  <td align="right">0.4%</td>
</tr>
<tr>
  <td align="right">SG</td>
  <td align="left">🇸🇬</td>
  <td align="right">110</td>
  <td align="right">0.4%</td>
</tr>
<tr>
  <td align="right">NZ</td>
  <td align="left">🇳🇿</td>
  <td align="right">99</td>
  <td align="right">0.4%</td>
</tr>
<tr>
  <td align="right">ZA</td>
  <td align="left">🇿🇦</td>
  <td align="right">97</td>
  <td align="right">0.4%</td>
</tr>
<tr>
  <td align="right">NO</td>
  <td align="left">🇳🇴</td>
  <td align="right">95</td>
  <td align="right">0.4%</td>
</tr>
<tr>
  <td align="right">AT</td>
  <td align="left">🇦🇹</td>
  <td align="right">91</td>
  <td align="right">0.4%</td>
</tr>
<tr>
  <td align="right">RU</td>
  <td align="left">🇷🇺</td>
  <td align="right">86</td>
  <td align="right">0.3%</td>
</tr>
<tr>
  <td align="right">DK</td>
  <td align="left">🇩🇰</td>
  <td align="right">84</td>
  <td align="right">0.3%</td>
</tr>
<tr>
  <td align="right">HU</td>
  <td align="left">🇭🇺</td>
  <td align="right">76</td>
  <td align="right">0.3%</td>
</tr>
<tr>
  <td align="right">GR</td>
  <td align="left">🇬🇷</td>
  <td align="right">64</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">UA</td>
  <td align="left">🇺🇦</td>
  <td align="right">56</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">IS</td>
  <td align="left">🇮🇸</td>
  <td align="right">49</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">AE</td>
  <td align="left">🇦🇪</td>
  <td align="right">49</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">GE</td>
  <td align="left">🇬🇪</td>
  <td align="right">44</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">PR</td>
  <td align="left">🇵🇷</td>
  <td align="right">44</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">LU</td>
  <td align="left">🇱🇺</td>
  <td align="right">42</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">IL</td>
  <td align="left">🇮🇱</td>
  <td align="right">42</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">PH</td>
  <td align="left">🇵🇭</td>
  <td align="right">41</td>
  <td align="right">0.2%</td>
</tr>
<tr>
  <td align="right">EE</td>
  <td align="left">🇪🇪</td>
  <td align="right">36</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">AR</td>
  <td align="left">🇦🇷</td>
  <td align="right">36</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">ID</td>
  <td align="left">🇮🇩</td>
  <td align="right">34</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">MY</td>
  <td align="left">🇲🇾</td>
  <td align="right">31</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">SI</td>
  <td align="left">🇸🇮</td>
  <td align="right">30</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">BZ</td>
  <td align="left">🇧🇿</td>
  <td align="right">29</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">TH</td>
  <td align="left">🇹🇭</td>
  <td align="right">29</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">RO</td>
  <td align="left">🇷🇴</td>
  <td align="right">25</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">VN</td>
  <td align="left">🇻🇳</td>
  <td align="right">24</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">LT</td>
  <td align="left">🇱🇹</td>
  <td align="right">24</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">MQ</td>
  <td align="left">🇲🇶</td>
  <td align="right">20</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">KR</td>
  <td align="left">🇰🇷</td>
  <td align="right">20</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">UN</td>
  <td align="left">🇺🇳</td>
  <td align="right">18</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">RS</td>
  <td align="left">🇷🇸</td>
  <td align="right">17</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">TN</td>
  <td align="left">🇹🇳</td>
  <td align="right">15</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">CL</td>
  <td align="left">🇨🇱</td>
  <td align="right">14</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">SK</td>
  <td align="left">🇸🇰</td>
  <td align="right">14</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">MX</td>
  <td align="left">🇲🇽</td>
  <td align="right">14</td>
  <td align="right">0.1%</td>
</tr>
<tr>
  <td align="right">CO</td>
  <td align="left">🇨🇴</td>
  <td align="right">11</td>
  <td align="right">0.0%</td>
</tr>
<tr>
  <td align="right">BD</td>
  <td align="left">🇧🇩</td>
  <td align="right">10</td>
  <td align="right">0.0%</td>
</tr>
<tr>
  <td align="right">EC</td>
  <td align="left">🇪🇨</td>
  <td align="right">10</td>
  <td align="right">0.0%</td>
</tr>
<tr>
  <td align="right">EG</td>
  <td align="left">🇪🇬</td>
  <td align="right">10</td>
  <td align="right">0.0%</td>
</tr>
</tbody>
</table>

<p>There are a few more rows but, in the spirit of privacy, I've not included some of the more unique countries. Not all of those are unique views - these are aggregate statistics. If your RSS reader is hosted in a different country - or on a large platform - it may only show up inaccurately.</p>

<p>If you don't see your country in this list, please <a href="https://edent.tel/">drop me a comment via your favourite method</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=71303&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/rss-club-where-are-you-from/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Vertically Aligning Roman Numerals in Code]]></title>
		<link>https://shkspr.mobi/blog/2026/05/vertically-aligning-roman-numerals-in-code/</link>
					<comments>https://shkspr.mobi/blog/2026/05/vertically-aligning-roman-numerals-in-code/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 03 May 2026 11:34:59 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=63775</guid>

					<description><![CDATA[I have a PHP function which uses Roman Numerals. It looks like this:  $romanNumerals = [     &#34;Ⅿ&#34;  =&#62; 1000,     &#34;ⅭⅯ&#34; =&#62; 900,     &#34;Ⅾ&#34;  =&#62; 500,     &#34;ⅭⅮ&#34; =&#62; 400,     &#34;Ⅽ&#34;  =&#62; 100,     &#34;ⅩC&#34; =&#62;  90,     &#34;Ⅼ&#34;  =&#62;  50,     &#34;ⅩⅬ&#34; =&#62; 40,     &#34;Ⅹ&#34;  =&#62; 10,     &#34;Ⅸ&#34;  =&#62; 9,     &#34;Ⅷ&#34; =&#62; 8,     &#34;Ⅶ&#34;  =&#62; 7,     &#34;Ⅵ&#34;  =&#62; 6,     &#34;Ⅴ&#34;   =&#62; 5,     &#34;Ⅳ&#34;  =&#62; 4,     &#34;Ⅲ&#34;  =&#62; 3,     &#34;Ⅱ&#34;  =&#62; 2,     &#34;Ⅰ&#34;   =&#62; 1 ];   The problem is, the…]]></description>
										<content:encoded><![CDATA[<p>I have a PHP function which uses Roman Numerals. It looks like this:</p>

<pre><code class="language-php">$romanNumerals = [
    "Ⅿ"  =&gt; 1000,
    "ⅭⅯ" =&gt; 900,
    "Ⅾ"  =&gt; 500,
    "ⅭⅮ" =&gt; 400,
    "Ⅽ"  =&gt; 100,
    "ⅩC" =&gt;  90,
    "Ⅼ"  =&gt;  50,
    "ⅩⅬ" =&gt; 40,
    "Ⅹ"  =&gt; 10,
    "Ⅸ"  =&gt; 9,
    "Ⅷ" =&gt; 8,
    "Ⅶ"  =&gt; 7,
    "Ⅵ"  =&gt; 6,
    "Ⅴ"   =&gt; 5,
    "Ⅳ"  =&gt; 4,
    "Ⅲ"  =&gt; 3,
    "Ⅱ"  =&gt; 2,
    "Ⅰ"   =&gt; 1
];
</code></pre>

<p>The problem is, the operators don't line up and the whole thing looks messy. Why? Because the <a href="https://shkspr.mobi/blog/2023/03/unicode-roman-numerals-and-screen-readers/">Unicode Roman Numerals</a> are <em>not</em> monospaced! <code>ⅭⅯ</code> is a different width to <code>ⅩC</code> and <code>Ⅷ</code> is only a single character!  Copy the above to a text editor and see if you can get neat columns. I bet you can't!</p>

<p>I'm obsessed with <a href="https://shkspr.mobi/blog/2014/11/why-i-vertically-align-my-code-and-you-should-too/">vertically aligning my code</a>. So how to solve this ugly problem?</p>

<p>The <a href="https://phpc.social/@Crell/115329116036130430">answer was simple</a>. Assign keys to the values and then flip the array!</p>

<pre><code class="language-php">$romanNumerals = array_flip([
    1000 =&gt; "Ⅿ",
     900 =&gt; "ⅭⅯ",
     500 =&gt; "Ⅾ",
     400 =&gt; "ⅭⅮ",
     100 =&gt; "Ⅽ",
      90 =&gt; "ⅩC",
      50 =&gt; "Ⅼ",
      40 =&gt; "ⅩⅬ",
      10 =&gt; "Ⅹ",
       9 =&gt; "Ⅸ",
       8 =&gt; "Ⅷ",
       7 =&gt; "Ⅶ",
       6 =&gt; "Ⅵ",
       5 =&gt; "Ⅴ",
       4 =&gt; "Ⅳ",
       3 =&gt; "Ⅲ",
       2 =&gt; "Ⅱ",
       1 =&gt; "Ⅰ"
]);
</code></pre>

<p>There! Doesn't that look much neater!</p>

<p><a href="https://libraries.mit.edu/150books/2011/05/11/1985/">As was written long ago</a>:</p>

<blockquote><p>A computer language is not just a way of getting a computer to perform operations but rather … it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute.</p></blockquote>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=63775&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/05/vertically-aligning-roman-numerals-in-code/feed/</wfw:commentRss>
			<slash:comments>1</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>43</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Let's Get Digging!]]></title>
		<link>https://shkspr.mobi/blog/2026/04/lets-get-digging/</link>
					<comments>https://shkspr.mobi/blog/2026/04/lets-get-digging/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 29 Apr 2026 11:34:23 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[history]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70665</guid>

					<description><![CDATA[As part of my quest to try new things I decided to dig for treasure in my local park.  The wonderful folks at DigVentures allow members of the public to assist with archaeology projects in their local area. We arrived on a sunny Thursday to find a couple of areas of Lesnes Abbey cordoned off, with the turf taken up, and a set of tools waiting for us.    After a suitable health-and-safety briefing …]]></description>
										<content:encoded><![CDATA[<p>As part of my quest to try new things I decided to dig for treasure in my local park.</p>

<p>The wonderful folks at <a href="https://digventures.com/">DigVentures</a> allow members of the public to assist with archaeology projects in their local area. We arrived on a sunny Thursday to find a couple of areas of <a href="https://digventures.com/projects/lesnes-abbey/">Lesnes Abbey</a> cordoned off, with the turf taken up, and a set of tools waiting for us.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/lesnes-abbey.webp" alt="Trenches cut out of the ground. A row of volunteers are bent over." width="2048" height="1152" class="aligncenter size-full wp-image-70691">

<p>After a suitable health-and-safety briefing and some instruction on the tools, we got cracking. I was slightly sceptical that we'd find anything digging only a few centimetres of dirt. The professionals reassured us that we'd all find something.</p>

<p>After scrabbling around for ages, I was feeling despondent. I found some interesting stones, some underwhelmed worms, and some prehistoric crisp packets - but nothing else.</p>

<p>And then.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/Tray-of-finds.webp" alt="A shallow plastic tray filled with old tile." width="2048" height="1536" class="aligncenter size-full wp-image-70692">

<p>CBM - Ceramic Building Material - tiles started popping out of the ground. Big orange chunks of ancient tiles were <em>everywhere</em>. My mate Cam and I also found some with holes in them - evidence of them being used on a roof.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/tezza-and-cam.webp" alt="Two grinning buffoons hold up a bit of old tile." width="2048" height="1536" class="aligncenter size-full wp-image-70697">

<p>A surprising number of oyster shells were present - the discarded detritus of someone's lunch from hundreds of years ago. I even found a tiny bone (assessed as non-human, thankfully. Apparently that comes with a hell of a lot of paperwork!).</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/things.webp" alt="Some shell and bone resting on an old tile." width="2048" height="1536" class="aligncenter size-full wp-image-70693">

<p>Gorgeous! And then, something shiny! Was it metal? Sadly, no. A chunk of pottery apparently. I kept digging, sraping, hoeing, looking, and then I found <em>more</em> shiny!</p>

<p><video width="720" height="1280" src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/shiny.mp4" muted="" autoplay="" loop=""></video></p>

<p>The local pottery expert reckoned it was <a href="https://en.wikipedia.org/wiki/Creamware">18th Century salt-glazed creamware</a>.</p>

<p>You can take a look at the <a href="https://digventures.com/projects/lesnes-abbey/timeline/">DigVentures Timeline</a> or the <a href="https://www.facebook.com/lesnesabbey/posts/pfbid02GtHhdPh6QUur8zGA1QeCMjSutovyLy84XiCorMUk3Js9EZcyX6HA4Ug4NetktbRCl">Lesnes Abbey Facebook page</a> to see more photos of what we all found.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/pointing.webp" alt="Me and another volunteer pointing excitedly into the dirt." width="1010" height="758" class="aligncenter size-full wp-image-70696">

<p>It was a brilliant day out - I never realised just how close under our feet you can find history. It was also a physically demanding day, lots of kneeling on the ground, heaving speades, dragging wheelbarrows, etc.</p>

<p>If they're running something near you, <a href="https://digventures.com/get-involved/">please get involved with DigVentures</a></p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70665&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/04/lets-get-digging/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://shkspr.mobi/blog/wp-content/uploads/2026/04/shiny.mp4" length="1704036" type="video/mp4" />

			</item>
		<item>
		<title><![CDATA[Theatre Review: Hadestown ★★★★★]]></title>
		<link>https://shkspr.mobi/blog/2026/04/theatre-review-hadestown/</link>
					<comments>https://shkspr.mobi/blog/2026/04/theatre-review-hadestown/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 27 Apr 2026 11:34:27 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[musical]]></category>
		<category><![CDATA[Theatre Review]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70681</guid>

					<description><![CDATA[Anaïs Mitchell has created something magical. I felt like giving a standing ovation after every song. Just pure theatrical joy delivered by a cast who know how to squeeze every drop of emotion from an audience.  Perhaps it was sitting right at the front of the stalls, but the opening of Hadestown feels like dinner theatre; almost cosy in its intimacy. The first act is so busy - there are a …]]></description>
										<content:encoded><![CDATA[<p><img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/hadestown-poster.webp" alt="Poster for Hadestown featuring a hand holding a budding flower." width="256" class="alignleft size-full wp-image-70682">
Anaïs Mitchell has created something magical. I felt like giving a standing ovation after every song. Just pure theatrical joy delivered by a cast who know how to squeeze every drop of emotion from an audience.</p>

<p>Perhaps it was sitting right at the front of the stalls, but the opening of Hadestown feels like dinner theatre; almost cosy in its intimacy. The first act is so <em>busy</em> - there are a hundred-and-one things happening on stage that it occasionally becomes overwhelming. The second act is slightly more intimate, but no less dazzling.</p>

<p>Having the musicians on stage lends to the feel of being in a nightclub. The stereo separation makes it easier to pick out the various musical threads and brings a lovely texture to the songs. Also, who knew a trombone could steal a show?</p>

<p>Lots of the cast sing in their natural accents. A roaring northern Hades versus a Mancunian Orpheus makes for quite the thrilling combination. Having subsequently listened to the Broadway cast recording, it is amazing what a positive difference it makes.</p>

<p>And, yes, the obligatory revolve spins the performers on a near-constant merry-go-round. When I am King of the West End, the revolve will be banned for the laze cliché that it is!</p>

<p>A stunning show with a killer soundtrack and a delightful set of performers.</p>

<p>I've written before about how the <a href="https://shkspr.mobi/blog/2024/12/the-art-of-the-pre-show-and-post-show/">pre-show and post-show experience</a> shapes an event. The Lyric theatre is generously sized, so plenty of space to mill about before the show, rather than being crammed into a tiny bar. The toilets weren't in <em>too</em> bad a condition. Once again, no set dressing in the liminal spaces. Would it have been so hard to mock up some travel posters for the eponymous station? Or have something for people to take photos with?</p>

<p>The <a href="https://nimax-theatres.mytoggle.io/shop/hadestown-cocktails-at-the-lyric-theatre">themed cocktail menu was inventive</a> but shockingly expensive, even for London prices. The programme is only a fiver and, unlike other West End shows, is full of interesting information and not just an excuse to cram in adverts - excellent value for money.</p>

<p>After the curtain call, we get a few more minutes with the musicians, which was delightful. On the way out there was no leaflet offering a discount on return visits (unlike <a href="https://shkspr.mobi/blog/2026/04/theatre-review-avenue-q/">Avenue Q</a>). There is, apparently, a "Hadestown Passport" which you can get stamped every visit - although I didn't see any evidence of that.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70681&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/04/theatre-review-hadestown/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[You can parse an .env file as an .ini with PHP - but there's a catch]]></title>
		<link>https://shkspr.mobi/blog/2026/04/you-can-parse-an-env-file-as-an-ini-with-php-but-theres-a-catch/</link>
					<comments>https://shkspr.mobi/blog/2026/04/you-can-parse-an-env-file-as-an-ini-with-php-but-theres-a-catch/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 25 Apr 2026 11:34:15 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=68636</guid>

					<description><![CDATA[The humble .env file is a useful and low-tech way of storing persistent environment variables. Drop the file on your server and let your PHP scripts consume it with glee.  But consume it how? There are lots of excellent parsing libraries for PHP. But isn&#039;t there a simpler way? Yes! You can use PHP&#039;s parse_ini_file() function and it works.  But…  .env and .ini have subtly different behaviour which …]]></description>
										<content:encoded><![CDATA[<p>The humble <code>.env</code> file is a useful and low-tech way of storing persistent environment variables. Drop the file on your server and let your PHP scripts consume it with glee.</p>

<p>But consume it <em>how</em>? There are lots of excellent parsing libraries for PHP. But isn't there a simpler way? Yes! You can use <a href="https://www.php.net/manual/en/function.parse-ini-file.php">PHP's <code>parse_ini_file()</code> function</a> and it works.</p>

<p>But…</p>

<p><code>.env</code> and <code>.ini</code> have subtly different behaviour which might cause you to swear at your computer.</p>

<p>Let's take this example:</p>

<pre><code class="language-env"># This is a comment
USERNAME="edent"
</code></pre>

<p>Run <code>$env = parse_ini_file( ".env" );</code> and you'll get back an array setting the USERNAME to be "edent". Hurrah! Works perfectly. Ship it!</p>

<p>But consider this:</p>

<pre><code class="language-env"># This is a comment
USERNAME="edent" # Don't use an @ symbol here.
</code></pre>

<p>It will happily tell you that the username is <code>"edent# Don"</code></p>

<p>WTAF?</p>

<p>Here's the thing. The comment character for <code>.ini</code> is <strong>not</strong> <code>#</code> - it's the semicolon <code>;</code></p>

<p>Let me give you some other examples of things which will fuck up your parsing:</p>

<pre><code class="language-env"># Documentation at https:/example.com/?doc=123
DOCUMENTATION=123
# Set the password
PASSWORD=qwerty;789
</code></pre>

<p>That gets us back this PHP array:</p>

<pre><code class="language-php">[
  '# Documentation at https:/example.com/?doc' =&gt; '123',
  'DOCUMENTATION' =&gt; '123',
  'PASSWORD' =&gt; 'qwerty',
];
</code></pre>

<p>When the <code>.ini</code> is parsed, it ignores every line which <em>doesn't have an <code>=</code> sign</em>. It also treats literal semicolons as the start of a new comment until they're wrapped in quotes.</p>

<p>My code highlighter should show you how it is parsed:</p>

<pre><code class="language-ini"># Documentation at https:/example.com/?doc=123
DOCUMENTATION=123
# Set the password
PASSWORD=qwerty;789
</code></pre>

<p>It gets worse. Consider this:</p>

<pre><code class="language-env"># Set the "official" name
REALNAME="Arthur, King of the Britons"
</code></pre>

<p>That immediately fails with <code>PHP Warning:  syntax error, unexpected '"' in envtest on line 1</code></p>

<p>You can use single quotes in pseudo-comments just fine, but if the ini parser sees a double quote without an equals then it throws a wobbly.</p>

<p>I'm sure there are several other gotchas as well. For example, there are <a href="https://www.w3schools.com/php/func_filesystem_parse_ini_file.asp">certain reserved words and symbols you can't used as a key</a>.</p>

<p>This will fail:</p>

<pre><code class="language-env"># Can we fix it? Yes we can!
FIX=true
</code></pre>

<p>It chokes on the exclamation point.</p>

<h2 id="how-to-solve-it-the-stupid-way"><a href="https://shkspr.mobi/blog/2026/04/you-can-parse-an-env-file-as-an-ini-with-php-but-theres-a-catch/#how-to-solve-it-the-stupid-way">How to solve it (the stupid way)</a></h2>

<p>The comments on an <code>.env</code> file start with a hash.</p>

<p>The comments on an <code>.ini</code> file start with a semicolon.</p>

<p>So, it is perfectly valid for a hybrid file to have its comments start with <code>#;</code></p>

<p>Look, if it's stupid but it works…</p>

<h2 id="what-have-we-learned-here-today"><a href="https://shkspr.mobi/blog/2026/04/you-can-parse-an-env-file-as-an-ini-with-php-but-theres-a-catch/#what-have-we-learned-here-today">What Have We Learned Here Today?</a></h2>

<ul>
<li>There's a right way and a wrong way to do <code>.env</code> parsing.</li>
<li>The wrong way works, up until the point it doesn't.</li>
<li>You should probably use a proper parser rather than hoping your <code>.env</code> looks enough like an <code>.ini</code> to pass muster.</li>
</ul>

<p>On next week's show - why you shouldn't store your passwords inside a JPEG!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=68636&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/04/you-can-parse-an-env-file-as-an-ini-with-php-but-theres-a-catch/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Does Mythos mean you need to shut down your Open Source repositories?]]></title>
		<link>https://shkspr.mobi/blog/2026/04/does-mythos-mean-you-need-to-shut-down-your-open-source-repos/</link>
					<comments>https://shkspr.mobi/blog/2026/04/does-mythos-mean-you-need-to-shut-down-your-open-source-repos/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 24 Apr 2026 11:34:30 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70599</guid>

					<description><![CDATA[Much Sturm und Drang in the world of Open Source with the announcement that the &#34;Mythos&#34; AI is now the ultimate hacker and is poised to unleash havoc on every code base.  So should you close all your Open Source projects to make them safe?  No.  Firstly, all your Open Source code has already been slurped up.  It was all ingested for &#34;training purposes&#34; years ago. If it was moderately interesting…]]></description>
										<content:encoded><![CDATA[<p>Much <i lang="de">Sturm und Drang</i> in the world of Open Source with the announcement that <a href="https://www.scientificamerican.com/article/what-is-mythos-and-why-are-experts-worried-about-anthropics-ai-model/">the "Mythos" AI is now the ultimate hacker</a> and is poised to unleash havoc on every code base.</p>

<p>So should you close all your Open Source projects to make them safe?</p>

<p>No.</p>

<p>Firstly, all your Open Source code has <em>already</em> been slurped up.</p>

<p>It was all ingested for "training purposes" years ago. If it was moderately interesting then it was backed-up by a digital hoarder. It has been archived by various digital libraries. Anyone who wants to do research on your code base can.</p>

<p>Closing now doesn't meaningfully protect you.</p>

<p>Secondly, most of the security holes in your systems are <em>probably</em> not in your code. Vulnerabilities exist throughout your supply chain. All the dependencies - your OS, libraries, and even hardware - are all richer targets for hackers. Finding a CVE in a popular library is almost certainly more worthwhile than investigating <em>your</em> Open Source code.</p>

<p>The bigger risk comes not from subtle logic bugs but from phishers, poor password hygiene, and insider threats. Securing your existing systems provides more protection than rushing to close-source your code.</p>

<p>Finally, closing the source of something doesn't protect you. These new AI models can easily investigate and your closed source systems and potentially penetrate them. It has always been possible to analyse websites and binaries. AI doesn't change that - although it might accelerate it.</p>

<p>Open Source does have risks but AI doesn't upend decades of evidence that closed-source is just as vulnerable to attackers.</p>

<p>In cases where the state creates code using public money, <a href="https://publiccode.eu/en/">it has a responsibly to share that code</a>. Automated threat analysis - even by hypercapabe AI - doesn't change that.</p>

<p>I would strongly recommend reading the UK's AI Safety Institute's <a href="https://www.aisi.gov.uk/blog/our-evaluation-of-claude-mythos-previews-cyber-capabilities">evaluation of Claude Mythos Preview’s cyber capabilities</a> and the <a href="https://www.ncsc.gov.uk/blogs/why-cyber-defenders-need-to-be-ready-for-frontier-ai">NCSC's advice</a>. Neither of them recommend closing down Open Source code.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70599&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/04/does-mythos-mean-you-need-to-shut-down-your-open-source-repos/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Sneaky spam in conversational replies to blog posts]]></title>
		<link>https://shkspr.mobi/blog/2026/04/sneaky-spam-in-conversational-replies-to-blog-posts/</link>
					<comments>https://shkspr.mobi/blog/2026/04/sneaky-spam-in-conversational-replies-to-blog-posts/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 23 Apr 2026 11:34:48 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[spam]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=70528</guid>

					<description><![CDATA[I&#039;m grateful that my blog posts attract lots of engaged, funny, and challenging comments. But any popular post also attracts spammers. I use Antispam Bee to automatically eradicate a couple of hundred crappy comments per day.    Nevertheless, some get through. Here&#039;s a particularly pernicious one - it appeared as three comments ostensibly in reply to each other.    At first glance these look like …]]></description>
										<content:encoded><![CDATA[<p>I'm grateful that my blog posts attract lots of engaged, funny, and challenging comments. But any popular post also attracts spammers. I use <a href="https://antispambee.pluginkollektiv.org/">Antispam Bee</a> to automatically eradicate a couple of hundred crappy comments <em>per day</em>.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/Antispam-Bee.webp" alt="Graph showing 272 comments blocked in a single day." width="762" height="292" class="aligncenter size-full wp-image-70529">

<p>Nevertheless, some get through. Here's a particularly pernicious one - it appeared as three comments ostensibly in reply to each other.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/04/spam-comments.webp" alt="First &quot;I read that article about why it’s so hard to passively track friends’ locations, and it actually makes sense. It talks about wanting automatic alerts when friends are nearby, but no app really does it well because of privacy and social awkwardness.&quot; Second &quot;Yeah, and even if the tech exists, people don’t always want to share their location 24/7. It’s like checking promos on spam domain promotions you might see potential, but there’s always uncertainty behind it. You’re kind of taking a chance on incomplete info.&quot; Third &quot;Exactly. Most location features are opt-in for a reason. Apps require consent because constantly tracking someone without them knowing would feel invasive, even if the intention is harmless.&quot;" width="2316" height="1598" class="aligncenter size-full wp-image-70530">

<p>At first glance these look like normal comments. They each address the content of the blog post albeit somewhat superficially. The first comment looks like it was from a social media post sharing my link - I get a lot of those as pingbacks, so it initially didn't trigger any suspicions from me.</p>

<p>The second is ostensibly a reply to the first and continues the conversation. Again, a bit shallow, but seems to be engaging in good faith.</p>

<p>The third looks like yet another reply. They all have unique email addresses, none of them have set their username to anything overly odd, and none of the users have filled out their URl.</p>

<p>But notice, in the second one, there's a link to a dodgy casino! There's no <code>https://</code> so it didn't jump out as a link.</p>

<p>All three came from the same IP address in the Philippines, so easy to block for now.</p>

<p>Each reply is spaced exactly 3 minutes apart which, in retrospect, looks a little odd.</p>

<p>Re-reading them carefully, they all look like AI slop. A plausible sounding summary, written in a casual style, but with very little semantic content. Seeing them as replies to each other primed me to think they were genuine because I'm used to spam coming in individual replies. Having the spam in the middle comment made it easy to glaze over.</p>

<p>Remember, there are no technological solutions to social problems. Sticking more and more barriers in the way of commenting only discourages genuine replies while the profit motive incentivises spammers to work around them.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=70528&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/04/sneaky-spam-in-conversational-replies-to-blog-posts/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			</item>
	</channel>
</rss>
