Shellsharks Blogroll - BlogFlock https://blogflock.com/list/xJ8yq 2026-10-20T22:34:34.000Z BlogFlock shellsharks Read "The Internet goes on high alert after discovery of 8 compromised TLS certs" - Molly White's activity feed 6ad7ec7a914413745263cc0d 2026-10-20T22:34:34.000Z Molly White <article class="entry h-entry hentry"><header><div class="description">Read: </div></header><div class="content e-content"><div class="article h-cite hcite"><div class="title"><a class="u-url u-repost-of" href="https://arstechnica.com/security/2026/10/the-internet-goes-on-high-alert-after-discovery-of-8-compromised-tls-certs/?utm_source=bsky&utm_medium=social" rel="bookmark">“<span class="p-name">The Internet goes on high alert after discovery of 8 compromised TLS certs</span>”</a>. </div><div class="byline"><span class="p-author h-card">Dan Goodin</span> in <i class="p-publication">Ars Technica</i>. <span class="read-date"> Published <time class="dt-published published" datetime="2026-10-20">October 20, 2026</time>.</span></div><blockquote class="summary p-summary entry-summary">“That is extremely in the ‘this should not be possible’ category,” Valdorda said. “Maybe some horribly dangerous key generation interface has a ‘size’ parameter and they set it to 1 by mistake???”</blockquote><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <time class="dt-published" datetime="2026-10-20T22:34:34+00:00" title="October 20, 2026 at 10:34 PM UTC">October 20, 2026 at 10:34 PM UTC</time>. </div></div></footer></article> AI can weaken relationships between people - and teams suffer as a result. - Werd I/O 6ad7a9bf7e1d7000013c2265 2026-10-20T17:49:51.000Z Werd I/O <p>Link: <a href="https://hbr.org/2026/10/team-dynamics-weaken-when-employees-turn-to-ai-instead-of-colleagues"><em>Team Dynamics Weaken When Employees Turn to AI Instead of Colleagues, by Kate Niederhoffer, Kristina Rapuano, Alex Liebscher, Alexi Robichaux and Jeffrey T. Hancock in Harvard Business Review</em></a></p><p>Relationships take time, effort, and practice to keep alive. So in a sense, it shouldn’t be a surprise to see this finding from a survey of more than a thousand desk workers across 20 industries:</p><blockquote>“The more they turned to AI instead of a teammate, the more their trust in each other and their ability to coordinate seemed to erode.”</blockquote><p>It turns out that if you start asking an AI system instead of your colleague, coordination and trust drop by at least 20%. These technologies are still relatively new; I imagine that over time this will continue to drop. People who feel isolated in their work today will feel more so as this trend solidifies. Similarly, people who feel untrusted today will only feel more so as their teams continue to ask AI systems instead of them.</p><p>That doesn’t mean AI is always inherently bad. Like all work processes, it demands that we think hard about culture: what kinds of behaviors and feelings do we want to promote? What’s important to the organization? And do we care more about an individual’s productivity than creating a high-performing team? (We shouldn’t.)</p><p>This also rings true:</p><blockquote>“People consistently underestimate how enjoyable a human conversation turns out to be. Whether the motivation is fear of judgment or a desire not to impose, avoiding a colleague is hardly a new workplace behavior. AI now provides an alluring alternative that forgoes the social and emotional costs of getting support.”</blockquote><p>One way we can counteract this is by making asking for help (and giving it) an explicit norm in our team cultures, and leading by example by doing it ourselves. In remote or hybrid teams that rely on tools like Slack, that also means doing it in a non-private channel, so that other team members can see it and it can become normalized.</p><p>Although a bit of a cliché and genuinely heinous if they’re done poorly, I think standups can also be really helpful here, if you can do them live. Here, everyone goes round a circle and talks briefly about what they’re working on, with explicit needs for help made as part of the update. Implicit requests for help can be answered once everyone has gone around the circle.</p><p>Can AI help? Totally. As the authors discuss in this piece, you can use technology to help conversations to happen asynchronously, particularly on teams that spread across multiple timezones, and it can actively facilitate connections between people.</p><p>Let’s do that, instead of displacing our people and our relationships. AI can be a facilitator between people, but it should never be an intermediator: our relationships, our communities, and our companies will suffer.</p> Foursquare died at the hands of private equity. What happens next? - Werd I/O 6ad79ac77e1d7000013c2243 2026-10-20T16:45:59.000Z Werd I/O <p>Link: <a href="https://teendrama.substack.com/p/some-final-words-on-foursquare?utm_id=97760_v0_s00_e0_tv4&just_subscribed=true"><em>Some final words on Foursquare, by Dennis Crowley</em></a></p><p>I freaking loved Foursquare. It was a wonderful way to explore cities with the help of my friends: in the same way that Upcoming was my best way of figuring out which events I should be going to, Foursquare let me know which restaurants, bars, parks, etc, were worth checking out. If Chris ranked a cocktail bar, you know it was amazing. Aaron always found the best coffee spots. And so on: my friends were better recommenders than any other source I had.</p><p>My own map lists every state and country I’ve been to over the last few decades. If I’m back in Amsterdam, I can figure out which Indonesian food place I really loved, because there it is on my map. (It’s <a href="https://paonbali.nl/">Paon Bali</a>, by the way. You’re welcome.)</p><p>So this was sad to see as an outcome. I think there are a bunch of important lessons here – not least the dangers of raising too much too soon without tethering the business to revenue. But at the same time, Foursquare launched during a startup explosion, and this kind of fundraising was the norm; I don’t fault Dennis for his decisions. The bigger problem seems to have been the private equity leadership more recently. I can’t think of a time when private equity <em>hasn’t</em> led to toxic leadership and a strip-mined company with an inequitable deal for employees.</p><p>Which leads me to an obvious problem. That check-in data is intimate stuff. It probably shouldn’t be something private equity can just inherit and do <em>whatever</em> with. Journalists and activists should hopefully not have been using Foursquare to check in; if they did, that data can almost certainly have been bought for analysis. And then a future-facing question: how might we have these kinds of social effects <em>without</em> sacrificing privacy?</p><p>Regardless, I’m pouring one out for Foursquare. I loved it. Thanks to everyone involved for building something that I found genuinely meaningful.</p> 2026-10-20 16:31: Hooman, we are ready to receive your apple core. 🍎 - Kev Quirk https://kevquirk.com/2026-10-20-1631 2026-10-20T15:31:00.000Z Kev Quirk <p>Hooman, we are ready to receive your apple core. 🍎</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/2026-10-20-1631/1000012549.webp" alt="1000012549" /></p> <div class="email-hidden"> <hr /> <p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p> <p>You can <a href="mailto:19gy@qrk.one?subject=2026-10-20%2016%3A31">reply to this post by email</a>, or <a href="https://kevquirk.com/2026-10-20-1631#comments">leave a comment</a>.</p> </div> Book Review: Quackery - A Brief History of the Worst Ways to Cure Everything by Lydia Kang ★★★⯪☆ - Terence Eden’s Blog https://shkspr.mobi/blog/?p=74296 2026-10-20T11:34:35.000Z Terence Eden’s Blog <img src="https://shkspr.mobi/blog/wp-content/uploads/2026/08/9781523501854.webp" alt="Book cover." width="200" class="alignleft size-full wp-image-74298"> <p>This is a charming and funny book all about the various ways humans have promoted fake medical cures in exchange for money.</p> <p>Despite the grim (and occasionally distressing) subject matter, the tone remains light and poppy throughout. There are lots of snarky asides (especially about the fake medical practitioners) and a real appreciation for the bizarre. It's fun the whole way through, although sometimes at the expense of people who perhaps didn't know better than to trust charlatans.</p> <p>One thing that is constantly brought back is how it can be hard to determine what <em>is</em> patent nonsense and what is a <i lang="la">bone fide</i> cure:</p> <blockquote><p>Prevent blood clotting: Extract mucus from the intestinal membranes of slaughtered pigs or from the lungs of slaughtered cows. Inject. (heparin)</p></blockquote> <p>Is that any more believable than injecting goat testicles to cure impotence?</p> <p>It also brings to light how squeamish we can be, especially when faced with unusual medical procedures:</p> <blockquote><p>We borrow other people’s wombs for surrogacy. And yet, plenty of people squirm at the idea of breastmilk banks. We are a society of contradictions.</p></blockquote> <p>The eBook is <em>beautifully</em> formatted. For once, images are in-line with the text! Usually in books of this sort, publishers treat the eBook like a mass-market paperback and stick the illustrations at the end.</p> <p>It ends rather abruptly, after taking us through light, electricity, colour therapy, animal magnetism, and a couple of dozen other "cure-alls"</p> <p>Sadly, there are no references or footnotes. While I have no reason to doubt the veracity of the claims, for a book about scientific misinformation and malpractice, I'd've expected a way to find out more information.</p> <img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=74296&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager"> Wonders of Web Weaving, Episode 24 - James' Coffee Blog https://jamesg.blog/2026/10/20/www-24 2026-10-20T00:00:00.000Z James' Coffee Blog <p><a href="https://web-weaving.jamesg.blog/24">The twenty-fourth episode of Wonders of Web Weaving is out</a>:</p> <blockquote> <p>In Episode 24, I chat with <a href="https://alexsirac.com">Alex</a>, the author of <a href="https://alexsirac.com">alexsirac.com</a> about, among other things, collective intelligence in public commons, what the IndieWeb can learn from Wikipedia, community in comments, and more.</p> </blockquote> <p>I hope you enjoy the episode!</p> <p><a href="https://web-weaving.jamesg.blog/subscribe/" rel="noreferrer"><em>Wonders of Web Weaving also has an RSS feed</em></a><em> you can use to follow along from wherever you get your podcasts.</em></p> <script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a4d68aa16febfced',t:'MTc5MjQ4Mzc3OA=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script> <a class="tag" href="https://alexsirac.com">Alex</a> <a class="tag" href="https://alexsirac.com">alexsirac.com</a> <a class="tag" href="https://web-weaving.jamesg.blog/24">The twenty-fourth episode of Wonders of Web Weaving is out</a> <a class="tag" href="https://web-weaving.jamesg.blog/subscribe/">Wonders of Web Weaving also has an RSS feed</a> contours - James' Coffee Blog https://jamesg.blog/2026/10/19/contours 2026-10-19T00:00:00.000Z James' Coffee Blog <p>Spectra of coherence — ground, sky; all presents. // Deconstruct.<br/> Where do I find the word that embodies a step?<br/> — elevation, propulsion, placing; in cycles, forward, forward.<br/> A mirror of irreducibility.<br/> How can a word reflect my cold nose, dripping with winter air,<br/> Breathing in fast, deeply.<br/> Stories, of moments — <br/> Collapsed colour, stark senses, every expression:<br/> Poem, no contours; possible?<br/> (But in contours definition exists.)</p> seen - James' Coffee Blog https://jamesg.blog/2026/10/19/seen 2026-10-19T00:00:00.000Z James' Coffee Blog <p>A flat sky<br/> Field of fog<br/> Hidden hills<br/> Echoes of snowfall —<br/> Not yet.</p><script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a4d03410e99dec6f',t:'MTc5MjQxNzMxOA=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script> A landmark study of AI in newsrooms reveals they need to be coaxed to experiment with their business models - Werd I/O 6ad55be517eda60001d0d9eb 2026-10-18T23:53:10.000Z Werd I/O <p>Link: <a href="https://cronkite.asu.edu/knightcenter/field-report-AI-in-news"><em>The News + AI Field Report, by Djordje Padejski for the Walter Cronkite School of Journalism and Mass Communication</em></a></p><p>The <a href="https://cronkite.asu.edu/knightcenter/field-report-AI-in-news">News + AI Field Report for 2022-2025</a>, produced by <a href="https://www.djordje.padejski.net/">Djordje Padejski</a> in conjunction with <a href="https://knightcenter.asu.edu/">ASU’s Knight Center for the Future of News</a>, is a landmark analysis of how newsrooms are experimenting with AI. The <a href="https://aimap.futureof.news/">interactive app</a> is also a really useful way to explore the 160 projects covered by this research.</p><p>I’ve been mulling over one of the findings described in the summary:</p><blockquote>“Newsrooms are most worried about the business threat from AI and have built the least for it. Interviews reveal widespread anxiety about the effects of AI on site traffic, audience behavior and news business models. Yet relatively few projects focus on revenue, subscriptions or fundraising.”</blockquote><p>20% of projects were business-related, but every fundraising project and over half of the business projects were grantees in the American Journalism Project’s AI programs. If those newsrooms are stripped out, the numbers drop significantly.</p><p>I think there’s a subtext worth talking about: I suspect the innovation projects listed here (that weren’t a part of a specific cohort) are a temperature check on how newsrooms are building technology / product experiments in general. If that’s the case, it implies that news is sticking to its comfort zone and spending much more time innovating on editorial concerns, and much less time experimenting with solutions for its existential business threats.</p><p>Reader-facing chatbots are a different angle on this: I’d call them a way for newsrooms to say they’re experimenting with AI without actually addressing a core user need. Newsroom websites are absolutely not where the chat layer should live (except, perhaps, for the use cases that provide deeper archive search for subscribers): AI users already have their own chatbots, which are the interfaces for <em>all</em> their AI-powered information. There are deeper ways AI could address user needs; the trick is that they would involve experimenting with the fundamental ways newsrooms do business. In turn, that requires both a willingness to do so, and much deeper collaboration between teams to make it happen.</p><p>So then the question becomes: how do we not just beef up journalism’s experiments in its business models, but the excitement and appetite to do so? Often the product teams that might be the owners of these kinds of experiments don’t (quite reasonably) own business models; how can those teams collaborate effectively? Funding from AJP clearly made a difference — is outside scaffolding required for this work to take place? How might product teams empower every team in the newsroom to run experiments?</p><p>These are much bigger questions than AI – and they’re questions newsrooms probably should be grappling with. In the meantime, I’m very grateful this analysis exists, and I hope it’s renewed to capture the year that follows.</p> 2026-10-18 13:22: Terence Eden asking on Mastodon what people's setups look like. Here's mine - 38" ultrawide... - Kev Quirk https://kevquirk.com/2026-10-18-1322 2026-10-18T12:22:00.000Z Kev Quirk <p>Terence Eden <a href="https://mastodon.social/@Edent/117461406670274597" rel="noopener noreferrer">asking on Mastodon</a> what people's setups look like. Here's mine - 38" ultrawide LG monitor that docks to my Framework 13, Fully standing desk, fish tank and motorbike helmets on the wall. I love my home office, but I do like heading into the office too.</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/2026-10-18-1322/PXL_20261018_121838452.webp" alt="PXL_20261018_121838452" /></p> <div class="email-hidden"> <hr /> <p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p> <p>You can <a href="mailto:19gy@qrk.one?subject=2026-10-18%2013%3A22">reply to this post by email</a>, or <a href="https://kevquirk.com/2026-10-18-1322#comments">leave a comment</a>.</p> </div> Year 4 at the Smallholding - Kev Quirk https://kevquirk.com/year-4-at-the-smallholding 2026-10-18T12:10:00.000Z Kev Quirk <p>So today marks the 4th anniversary of us moving to our 2.5 acre smallholding in north Wales. I can't believe it's been 4 years already - it feels like 5 minutes ago that I wad writing my <a href="https://kevquirk.com/year-3-at-the-smallholding">3 years at the smallholding post</a>.</p> <p>Last year's update wasn't as positive as previous years thanks to us having to get a new roof, which cost a shit tonne of money, and caused leaks all over the house. But I'm happy to say that the update for this year is mostly positive. I ended last year's post by saying:</p> <blockquote> <p>If next year I can get the polytunnel and conservatory done, I'll class that as a win. I'd love to get a quad bike for towing the flail too, but again...money.</p> </blockquote> <p>Unfortunately there's no poly tunnel, no insulation in the conservatory, and no quad bike in the barn. Let me explain...</p> <h2>Goats</h2> <p>In March of this year we decided it would be a good idea to get some goats. My wife had been talking to a goat farmer in mid-Wales for a few months, and we decided the time was right to get some. So we ordered 4 male pygmy goats and brought them home in the back of the car!</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/year-4-at-the-smallholding/goats-home-car.webp" alt="goats-home-car" /> <em>Our first 4 goats arriving home</em></p> <p>While we were at the farm, the farmer showed us a beautiful half pygmy, half "normal" goat and her 2 kids, along with a little pygmy goat that followed her around like a lost puppy. We immediately warmed to all of them, but we couldn't fit them in the car, so we had to pass.</p> <p>After a week or so of thinking about them, my wife decided to head back down there and pick them up too. So we ended up with 8 goats all together. I'm <em>really</em> glad that my wife decided to get the second batch, as the mum (now called Betsy) is so friendly and one of my favourite of the group.</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/year-4-at-the-smallholding/betsy.webp" alt="betsy" /> <em>Betsy being lovely (as usual)</em></p> <h3>Improving their home</h3> <p>We're very lucky to have a pair of stables at the back of our property, one was already used by the chickens, so we setup the other for the goats. However, the stables and surrounding needed some work. We had to:</p> <ul> <li>Install a land drain and level the ground</li> <li>Extend the hard standing around the stables</li> <li>Get some fencing installed</li> <li>Replace the doors and windows</li> <li>Install ventilation and power</li> <li>Create a "rock wall" for the goats to play on</li> </ul> <p>Unfortunately this all took up what little budget we had left following the roof, so the poly tunnel and insulation in the conservatory had to wait.</p> <p>We completed the renovations on the stables and both the chickens and the goats now have a lovely little home that has lots of space, but (more importantly) meets their needs.</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/year-4-at-the-smallholding/goats-and-chickens.webp" alt="goats-and-chickens" /> <em>Goats and chickens on the rock wall</em></p> <p>Here's a little gallery of how the work progressed on the stables:</p> <div class="gallery"> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-00.webp" class="gallery-link" data-pb-lightbox data-caption="Land drain installed and ground leveled"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-00.webp" alt="stables-00" loading="lazy"> </a> <figcaption class="gallery-caption">Land drain installed and ground leveled</figcaption> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-01.webp" class="gallery-link" data-pb-lightbox data-caption="Extended hard standing around the stables"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-01.webp" alt="stables-01" loading="lazy"> </a> <figcaption class="gallery-caption">Extended hard standing around the stables</figcaption> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-02.webp" class="gallery-link" data-pb-lightbox data-caption="Fencing being installed"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-02.webp" alt="stables-02" loading="lazy"> </a> <figcaption class="gallery-caption">Fencing being installed</figcaption> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-03.webp" class="gallery-link" data-pb-lightbox data-caption="New windows and doors being installed"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-03.webp" alt="stables-03" loading="lazy"> </a> <figcaption class="gallery-caption">New windows and doors being installed</figcaption> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-04.webp" class="gallery-link" data-pb-lightbox data-caption="All finished...ish"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-04.webp" alt="stables-04" loading="lazy"> </a> <figcaption class="gallery-caption">All finished...ish</figcaption> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-05.webp" class="gallery-link" data-pb-lightbox data-caption="Bonus photo of a happy Lando sitting in his food bowl"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/stables-05.webp" alt="stables-05" loading="lazy"> </a> <figcaption class="gallery-caption">Bonus photo of a happy Lando sitting in his food bowl</figcaption> </figure> </div> <h2>Chickens</h2> <p>As well as goats, we decided to add to our flock of chickens, but instead of just buying more we wanted to do it a little differently. We have a rooster now, so all our eggs are fertilised and we decided to try and hatch some eggs instead. We also wanted to get something a little different, so my wife bought some guinea fowl eggs, which we put under a broody hen to see if they would hatch. They did, and we ended up with 5 beautiful (but noisy) guinea fowl.</p> <div class="gallery"> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/fowl-01.webp" class="gallery-link" data-pb-lightbox data-caption="Three of the fowl keets"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/fowl-01.webp" alt="fowl-01" loading="lazy"> </a> <figcaption class="gallery-caption">Three of the fowl keets</figcaption> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/fowl-02.webp" class="gallery-link" data-pb-lightbox data-caption="The other 2 with their adopted mum, Nugget"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/fowl-02.webp" alt="fowl-02" loading="lazy"> </a> <figcaption class="gallery-caption">The other 2 with their adopted mum, Nugget</figcaption> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/fowl-03.webp" class="gallery-link" data-pb-lightbox data-caption="4 of the 5 fowl today, still with Nugget"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/fowl-03.webp" alt="fowl-03" loading="lazy"> </a> <figcaption class="gallery-caption">4 of the 5 fowl today, still with Nugget</figcaption> </figure> </div> <p>The guinea fowl were a great success - 5 of the 6 eggs hatched. So we decided to attempt the same thing with some of our chicken eggs, especially since a fox had gotten one of the hens and we wanted to hatch some of her eggs. Unfortunately we had no broody hens at the time, so we decided to buy an incubator and cheat.</p> <div class="gallery"> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/chickens-01.webp" class="gallery-link" data-pb-lightbox data-caption="chickens-01"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/chickens-01.webp" alt="chickens-01" loading="lazy"> </a> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/chickens-02.webp" class="gallery-link" data-pb-lightbox data-caption="chickens-02"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/chickens-02.webp" alt="chickens-02" loading="lazy"> </a> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/chickens-03.webp" class="gallery-link" data-pb-lightbox data-caption="chickens-03"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/chickens-03.webp" alt="chickens-03" loading="lazy"> </a> </figure> </div> <p>We attempted to hatch 12 eggs, but only 3 were successful unfortunately. We think 2 of them are roosters too, so we will see how that goes as they grow up and undoubtedly challenge their dad. We're thinking about doing it again this spring, but we're worried about having a plethora of roosters and what we will ultimately have to do to them. 💀</p> <p>Finally I installed some new perches for the chickens to roost on in the evening. Below is a removable shelf that makes things <em>way</em> easier to clean.</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/year-4-at-the-smallholding/chicken-perch.webp" alt="chicken-perch" /></p> <h2>Another blow</h2> <p>So at this point we had used up <em>everything</em> we had saved. We had literally nothing in our savings account. Then we noticed that our older dog, Tia, who's 14, was getting very smelly breath and whenever she was chewing her favourite ball, her mouth was bleeding.</p> <p>So we took her to the vets and they told us she had a fairly common type of benign tumour growing in her mouth. Although it was benign, it was <em>very</em> aggressive and if left untreated she would have 6-12 months if she was lucky. And it would be a very uncomfortable end for her.</p> <p>We had to get it looked at, but this was going to cost <em>thousands</em> and in a 14 year old dog, I wasn't sure if it was worth it. The last thing we wanted was to put her through all this only to find out in a few months that she had another terminal condition that would end her life anyway.</p> <p class="notice">I know that sounds heartless, but I think at times like this it's important to be practical and take into account how much the dog will suffer, and whether we're doing it for us, or them.</p> <p>She needed a CT scan on her jaw to see if surgery was viable, so we decided to get a full body CT scan done instead. This would give us a good indication if anything else untoward was going on in her body. Lucky for us the CT came back all clear and the surgery on her jaw was viable, so we went ahead.</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/year-4-at-the-smallholding/tia-01.webp" alt="tia-01" /></p> <p><img loading="lazy" src="https://kevquirk.com/content/images/year-4-at-the-smallholding/tia-02.webp" alt="tia-02" /></p> <p>Three operations, 1 infection, and lots of discomfort later for poor Tia, and she's now fully recovered after having around 40% of her lower jaw removed. Unfortunately for her, this means her rather large tongue often dangles out of her mouth these days. But we think she's still gorgeous.</p> <p><img loading="lazy" src="https://kevquirk.com/content/images/year-4-at-the-smallholding/tia-03.webp" alt="tia-03" /></p> <p>As if this wasn't punishment enough, we also got a new puppy, Nelly, at the same time that Tia was going through all this. So managing a sick dog, a new puppy, and keeping 2 kids entertained during their summer holidays really wasn't a fun time.</p> <div class="gallery"> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/nelly-01.webp" class="gallery-link" data-pb-lightbox data-caption="nelly-01"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/nelly-01.webp" alt="nelly-01" loading="lazy"> </a> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/nelly-02.webp" class="gallery-link" data-pb-lightbox data-caption="nelly-02"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/nelly-02.webp" alt="nelly-02" loading="lazy"> </a> </figure> <figure class="gallery-item"> <a href="https://kevquirk.com/content/images/year-4-at-the-smallholding/all-3-dogs.webp" class="gallery-link" data-pb-lightbox data-caption="all-3-dogs"> <img src="https://kevquirk.com/content/images/year-4-at-the-smallholding/all-3-dogs.webp" alt="all-3-dogs" loading="lazy"> </a> </figure> </div> <p>We had bought Nelly way before we knew Tia was sick. The kids knew she was coming, and we had all met Nell multiple times. So although we knew it would be a nightmare, we didn't want to renege on buying her. Let me tell you, dear reader, it was <em>rough</em>. Like, <em>really</em> rough, but we're glad we stuck it out because Nelly is beautiful and such a wonderful addition to our family.</p> <h2>What's next?</h2> <p>Tia's surgery ended up costing us around £6,000 (~$8,000). We already had no money, so it had to go on a credit card, which we will pay off over the next few months.</p> <p>Our plans for year 5 are the same as year 4, I think - we'd love to get a poly tunnel in and the roof in the conservatory insulated so we can use it all year round. But we will need to see how the finances go - hopefully there will be no more unexpected expenses for a little while. We can only hope.</p> <p>In the meantime we continue to enjoy our brood of various animals and the little plot we call home.</p> <div class="email-hidden"> <hr /> <p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p> <p>You can <a href="mailto:19gy@qrk.one?subject=Year%204%20at%20the%20Smallholding">reply to this post by email</a>, or <a href="https://kevquirk.com/year-4-at-the-smallholding#comments">leave a comment</a>.</p> </div> Una Watch TOTP - MFA on your wrist! - Terence Eden’s Blog https://shkspr.mobi/blog/?p=76104 2026-10-18T11:34:08.000Z Terence Eden’s Blog <p>Let's get this out of the way first - this is a <em>terrible</em> idea! I want my two-factor authentication codes to be easily accessible to me, so I've built a watch app which will display them. That's really convenient for me - but makes for a terrible security posture. Anyone who steals my watch will be able to see my one-time code. If they're clever, they can decompile the app and find the secret which powers the code generation.</p> <p>You should absolutely not do this and, if you ignore my warnings, you should only do this for codes which aren't critical to your security.</p> <!-- 👋👋👋👋👋👋👋👋👋 Welcome to Comment Club! If this is your first time - hello! This content is only available to sophisticated nerds who read my HTML comments. You know what? I *do* use this. I have a low-ish security account which constantly needs my MFA number. Sometimes I can't be bothered unlocking my phone to get it. Of course, on my wrist I save it under a different name. Perhaps I'm an idiot for doing so, but sometimes convenience wins. Anyway, the three rules of Comment Club are… 1. You must not tell anyone about Comment Club - let them find out about it themselves. 2. You *must* add some Comment Club Content to at least one of your blog posts. Doesn't have to be much, just a little note will do. 3. You should drop an email to anyone whose comments you've read. Start by sending me a friendly message at comment.club@shkspr.mobi Keep your eyes peeled for more comments in my other blog posts 😃 TTFN. --> <p>In my defence, an attacker would still need my username and password to make any use of these codes - but please don't trust your security to my deranged witterings.</p> <h2 id="what-it-looks-like"><a href="https://shkspr.mobi/blog/2026/10/una-watch-totp-mfa-on-your-wrist/#what-it-looks-like">What It Looks Like</a></h2> <img src="https://shkspr.mobi/blog/wp-content/uploads/2026/09/MFA.webp" alt="My wristwatch showing "HSBC MFA Code 751646". Don't worry, this isn't my real code. OR IS IT?!?!" width="1024" height="576" class="aligncenter"> <h2 id="prior-art"><a href="https://shkspr.mobi/blog/2026/10/una-watch-totp-mfa-on-your-wrist/#prior-art">Prior Art</a></h2> <p>I'm sure many other people have done this. Indeed, three years ago I built <a href="https://shkspr.mobi/blog/2023/07/an-eink-wrist-mounted-totp-generator/">An eInk, Wrist-Mounted, TOTP Generator</a>.</p> <img src="https://shkspr.mobi/blog/wp-content/uploads/2023/07/Wrist-TOTP.jpg" alt="A chunky wristwatch showing the time and a selection of 6 digit codes and their corresponding entities." width="1024" height="1024" class="aligncenter"> <h2 id="the-service"><a href="https://shkspr.mobi/blog/2026/10/una-watch-totp-mfa-on-your-wrist/#the-service">The Service</a></h2> <p>This is in my <code>Service.cpp</code> - as you can see, it's pretty simple. This won't let you add in hundreds of codes - you get one and that's it. There's no countdown when a code is about to expire, so I recommend waiting until a new one pops up before you start typing it in.</p> <p>I'll be candid, I haven't used C++ properly since university - and that was in the last century. I've mostly just cut things out to see what breaks. Feel free to educate me on the correct idiomatic code.</p> <p>You will need to set your own secret in here.</p> <pre><code class="language-cpp">// Standard includes. #include "Service.hpp" #include "SDK/Messages/CommandMessages.hpp" #include "SDK/Messages/MessageGuard.hpp" // Needed for PureTOTP. #include <iostream> #include "TOTP.h" #include <string> #include <sstream> // What this Glance can do. Service::Service(SDK::Kernel &kernel) : mKernel(kernel) , mGlanceUI() , mGlanceTitle() , mGlanceValue() {} void Service::createGuiControls() { // Set the main title in the Glance. mGlanceTitle = mGlanceUI.createText(); mGlanceTitle.pos({ kTitleX, kTitleY }, { kTitleW, kTitleH }) .font(GlanceFont_t::GLANCE_FONT_POPPINS_SEMIBOLD_20) .color(GlanceColor_t::GLANCE_COLOR_TEAL) .setText("HSBC MFA Code") .alignment(GlanceAlignH_t::GLANCE_ALIGN_H_CENTER); // Set the default text for the value. mGlanceValue = mGlanceUI.createText(); mGlanceValue.pos({ 20, kValueY }, { 200, kValueH }) .font(GlanceFont_t::GLANCE_FONT_POPPINS_SEMIBOLD_20) .color(GlanceColor_t::GLANCE_COLOR_YELLOW_DARK) .setText( "Waiting for update" ) .alignment(GlanceAlignH_t::GLANCE_ALIGN_H_CENTER); } void Service::glanceUpdate() { // Set the Base32 encoded secret (all uppercase). std::string secret = "QWERTYUIOP"; // Generate the code based on the Unix timestamp right now. const std::time_t t = std::time(0); std::string code = TOTP::GenerateTOTP( 6, 30, TOTP::HMAC_SHA1, secret, t ); std::ostringstream ss; ss << t; // Convert the string to char* and display it as the value. mGlanceValue.print( code.c_str() ); // Show the Unix time to check the timezone is correct. // mGlanceTitle.print( ss.str().c_str() ); } // No service. Service::~Service(){} // When this glance is opened. void Service::run() { while (true) { SDK::MessageBase *msg; if(!mKernel.comm.getMessage(msg)) { continue; } switch (msg->getType()) { // The Glance has started. case SDK::MessageType::EVENT_GLANCE_START: if (configGui()) { createGuiControls(); } else { mKernel.comm.releaseMessage(msg); mKernel.sys.exit(0); } break; // The Glance has been stopped. case SDK::MessageType::COMMAND_APP_STOP: case SDK::MessageType::EVENT_GLANCE_STOP: mKernel.comm.releaseMessage(msg); return; break; // Every second, perform an action. case SDK::MessageType::EVENT_GLANCE_TICK: onGlanceTick(); break; default: break; } mKernel.comm.releaseMessage(msg); } } void Service::onGlanceTick() { if (mGlanceUI.isInvalid()) { if (auto upd = SDK::make_msg<SDK::Message::RequestGlanceUpdate>(mKernel)) { upd->name = APP_NAME; upd->controls = mGlanceUI.data(); upd->controlsNumber = static_cast<uint32_t>(mGlanceUI.size()); upd.send(100); } mGlanceUI.setValid(); } glanceUpdate(); } bool Service::configGui() { bool status = false; if (auto gc = SDK::make_msg<SDK::Message::RequestGlanceConfig>(mKernel)) { if (gc.send(100) && gc.ok()) { if (gc->maxControls >= 3) { mGlanceUI.setWidth(gc->width); mGlanceUI.setHeight(gc->height); status = true; } } } return status; } </code></pre> <h2 id="the-library"><a href="https://shkspr.mobi/blog/2026/10/una-watch-totp-mfa-on-your-wrist/#the-library">The Library</a></h2> <p>There are dozens of C++ libraries for RFC 6238 generation. I ended up using <a href="https://github.com/Einztein/PureTOTP">PureTOTP</a> as it didn't require any external dependencies and was only two files. As I only needed SHA1 TOTP codes, I stripped out a bunch of functionality which was unnecessary for me. Similarly, I only wanted to generate 6 digit codes with a 30 second period - so took out anything which did more than that.</p> <p>I've tidied up the code and comments where I can. The original was MIT Licenced - so this is as well.</p> <p>There are two parts to this. First, the header</p> <pre><code class="language-_">// TOTP.h // #pragma once #include <string> class TOTP { public: const static int HMAC_SHA1 = 20; // Length of HMAC. static std::string GenerateTOTP(const std::string& secret); static std::string GenerateTOTP(int digit, int refreshSeconds, int algorithm, const std::string& secret, int specTime); TOTP(int digit, int refreshSeconds, int algorithm, const std::string& secret): digit(digit), refreshSeconds(refreshSeconds), algorithm(algorithm), secret(secret) {} TOTP(const std::string& secret): digit(6), refreshSeconds(30), algorithm(HMAC_SHA1), secret(secret) {} std::string currentTOTP(); private: int digit, refreshSeconds, algorithm; std::string secret; }; </code></pre> <p>Next is the standalone library which does the TOTP generation, <code>TOTP.cpp</code></p> <pre><code class="language-cpp">// TOTP.cpp // #include "TOTP.h" #include <vector> #include <stack> #include <queue> #include <sstream> #include <iomanip> #include <cstdint> #include <cstring> #include <array> #include <stdexcept> #include <algorithm> using namespace std; struct JEVP_MD { enum Kind { SHA1 }; Kind kind; int md_size; int block_size; }; static inline uint32_t rotl32(uint32_t x, uint32_t n) { return (x << n) | (x >> (32 - n)); } static inline uint32_t rotr32(uint32_t x, uint32_t n) { return (x >> n) | (x << (32 - n)); } static inline uint64_t rotr64(uint64_t x, uint64_t n) { return (x >> n) | (x << (64 - n)); } static uint32_t load_be32(const unsigned char* p) { return (uint32_t(p[0]) << 24) | (uint32_t(p[1]) << 16) | (uint32_t(p[2]) << 8) | uint32_t(p[3]); } static void store_be32(uint32_t v, unsigned char* p) { p[0] = static_cast<unsigned char>((v >> 24) & 0xFF); p[1] = static_cast<unsigned char>((v >> 16) & 0xFF); p[2] = static_cast<unsigned char>((v >> 8) & 0xFF); p[3] = static_cast<unsigned char>( v & 0xFF); } static void store_be64(uint64_t v, unsigned char* p) { p[0] = static_cast<unsigned char>((v >> 56) & 0xFF); p[1] = static_cast<unsigned char>((v >> 48) & 0xFF); p[2] = static_cast<unsigned char>((v >> 40) & 0xFF); p[3] = static_cast<unsigned char>((v >> 32) & 0xFF); p[4] = static_cast<unsigned char>((v >> 24) & 0xFF); p[5] = static_cast<unsigned char>((v >> 16) & 0xFF); p[6] = static_cast<unsigned char>((v >> 8) & 0xFF); p[7] = static_cast<unsigned char>( v & 0xFF); } static vector<unsigned char> sha1_hash(const unsigned char* data, size_t len) { vector<unsigned char> msg(data, data + len); uint64_t bit_len = static_cast<uint64_t>(len) * 8; msg.push_back(0x80); while ((msg.size() % 64) != 56) msg.push_back(0x00); unsigned char lenbuf[8]; store_be64(bit_len, lenbuf); msg.insert(msg.end(), lenbuf, lenbuf + 8); uint32_t h0 = 0x67452301; uint32_t h1 = 0xEFCDAB89; uint32_t h2 = 0x98BADCFE; uint32_t h3 = 0x10325476; uint32_t h4 = 0xC3D2E1F0; for (size_t chunk = 0; chunk < msg.size(); chunk += 64) { uint32_t w[80]; for (int i = 0; i < 16; ++i) w[i] = load_be32(&msg[chunk + i * 4]); for (int i = 16; i < 80; ++i) w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); uint32_t a = h0, b = h1, c = h2, d = h3, e = h4; for (int i = 0; i < 80; ++i) { uint32_t f, k; if (i < 20) { f = (b & c) | ((~b) & d); k = 0x5A827999; } else if (i < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; } else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } else { f = b ^ c ^ d; k = 0xCA62C1D6; } uint32_t temp = rotl32(a, 5) + f + e + k + w[i]; e = d; d = c; c = rotl32(b, 30); b = a; a = temp; } h0 += a; h1 += b; h2 += c; h3 += d; h4 += e; } vector<unsigned char> out(20); store_be32(h0, &out[ 0]); store_be32(h1, &out[ 4]); store_be32(h2, &out[ 8]); store_be32(h3, &out[12]); store_be32(h4, &out[16]); return out; } static const JEVP_MD g_sha1 = {JEVP_MD::SHA1, 20, 64}; const JEVP_MD* JEVP_sha1() { return &g_sha1; } unsigned char* JHMAC(const JEVP_MD* JEVP_MD, const void* key, int key_len, const unsigned char* data, size_t data_len, unsigned char* md, unsigned int* md_len) { if (!JEVP_MD || !key || key_len < 0 || !data) return nullptr; static thread_local unsigned char static_md[64]; if (!md) md = static_md; vector<unsigned char> key_block(JEVP_MD->block_size, 0); const unsigned char* key_bytes = static_cast<const unsigned char*>(key); vector<unsigned char> real_key; if (key_len > JEVP_MD->block_size) { real_key = sha1_hash(key_bytes, static_cast<size_t>(key_len)); std::copy(real_key.begin(), real_key.end(), key_block.begin()); } else { std::copy(key_bytes, key_bytes + key_len, key_block.begin()); } vector<unsigned char> ipad(JEVP_MD->block_size); vector<unsigned char> opad(JEVP_MD->block_size); for (int i = 0; i < JEVP_MD->block_size; ++i) { ipad[i] = static_cast<unsigned char>(key_block[i] ^ 0x36); opad[i] = static_cast<unsigned char>(key_block[i] ^ 0x5C); } vector<unsigned char> inner; inner.reserve(JEVP_MD->block_size + data_len); inner.insert(inner.end(), ipad.begin(), ipad.end()); inner.insert(inner.end(), data, data + data_len); vector<unsigned char> inner_hash = sha1_hash(inner.data(), inner.size()); vector<unsigned char> outer; outer.reserve(JEVP_MD->block_size + inner_hash.size()); outer.insert(outer.end(), opad.begin(), opad.end()); outer.insert(outer.end(), inner_hash.begin(), inner_hash.end()); vector<unsigned char> final_hash = sha1_hash(outer.data(), outer.size()); std::memcpy(md, final_hash.data(), final_hash.size()); if (md_len) *md_len = static_cast<unsigned int>(final_hash.size()); return md; } // Base32 decoding table. /* clang-format off */ const int base32_reverse_map[128] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 15 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 31 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 47 // (49) 2 3 4 5 6 7 (56) 255, 255, 26, 27, 28, 29, 30, 31, 255, 255, 255, 255, 255, 255, 255, 255, // 63 // (64) A B C D E F G H I J K L M N O 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 79 // P Q R S T U V W X Y Z (91) 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // 95 // (96) A B C D E F G H I J K L M N O // lower case instead 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 111 // P Q R S T U V W X Y Z (123) // lower case instead 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255 // 127 }; /* clang-format on */ // Base32 decoding function. vector<unsigned char> base32_decode(const string& base32) { queue<int> q_rev; for (const char& c : base32) { if (c <= 49 || (c >= 56 && c <= 64) || (c >= 91 && c <= 96) || c >= 123) { // Illegal lower case will be treat as upper case thanks to base32_reverse_map. if (c == '=') break; } else { q_rev.push(base32_reverse_map[(int)c]); // Get integers of base32. } } queue<bool> q_bin; while (!q_rev.empty()) // Transform the integers into bits and queue them up. { int now = q_rev.front(); // Get a integer from queue. q_rev.pop(); stack<bool> sb; for (int i = 0; i < 5; i++) // Push the bits of this integer into stack { // 5 bits into 1 group sb.push(now & 1); // Push the last bit of this integer into stack. now >>= 1; // Flush the last bit. } while (!sb.empty()) // Flush the bits of this integer into binary queue. { q_bin.push(sb.top()); // Pop bits from stack into binary queue. sb.pop(); } } vector<unsigned char> uc; while (!q_bin.empty()) // Transform the bits into bytes. { int thehex = 0; for (int i = 0; i < 8; i++) // Read a byte from the bits queue. { if (q_bin.empty()) { // If the bits queue is empty now, thehex <<= 8 - i; // set 0 on the last bits of a byte. break; } thehex <<= 1; // Make the space for the new bit. thehex |= (int)q_bin.front(); // Push this bit into byte. q_bin.pop(); } uc.push_back((unsigned char)thehex); } if (uc.back() == 0) uc.pop_back(); // TOTP may abandon last zero. if (uc.size() % 2 != 0) uc.pop_back(); // TOTP may abandon odd res. return uc; } // Get Unix Time. time_t getUnixTime() { return time(0); } // Calculate the TOTP time signature. time_t getTimeSign(int refreshPeriod, time_t specUnixTime) { time_t outTime = specUnixTime / refreshPeriod; return outTime; } // Transform time_t aka <long long> to bytes. vector<unsigned char> llong2bytes(time_t tt) { uint64_t value = static_cast<uint64_t>(tt); vector<unsigned char> bytes(8); for (int i = 7; i >= 0; --i) { bytes[i] = static_cast<unsigned char>(value & 0xFF); value >>= 8; } return bytes; } // Fast Exponentiation algorithm. unsigned fastpow(unsigned base, unsigned index) { if (index == 0) return 1; unsigned t = 1; while (index != 0) { if (index & 1) t *= base; index >>= 1; base *= base; } return t; } // Calculate TOTP according to RFC standard. std::string hash_to_TOTP(const unsigned char* hmac, unsigned int length, int digit) { int offset = hmac[length - 1] & 0x0F; uint32_t bin_code = ((hmac[offset] & 0x7F) << 24) | ((hmac[offset + 1] & 0xFF) << 16) | ((hmac[offset + 2] & 0xFF) << 8) | ( hmac[offset + 3] & 0xFF); uint32_t mod = 1; for (int i = 0; i < digit; ++i) mod *= 10; uint32_t otp = bin_code % mod; std::ostringstream oss; oss << std::setw(digit) << std::setfill('0') << otp; return oss.str(); } std::string TOTP::GenerateTOTP(const std::string& secret) { return GenerateTOTP(6, 30, HMAC_SHA1, secret, getUnixTime()); } std::string TOTP::GenerateTOTP(int digit, int refreshSeconds, int algorithm, const std::string& secret, int specTime) { vector<unsigned char> h_msg = llong2bytes(getTimeSign(refreshSeconds, specTime)); // Get current time signature and transform time_t aka <long long> to bytes. vector<unsigned char> h_key = base32_decode(secret); // Transform base32 encoded secret key to decoded bytes. unsigned char* out_hmac = new unsigned char[algorithm]; // Perform openssl function to calculate HMAC-SHA1 hash. unsigned int out_hmac_length; const JEVP_MD* emd; emd = JEVP_sha1(); JHMAC(emd, h_key.data(), (int)h_key.size(), h_msg.data(), (int)h_msg.size(), out_hmac, &out_hmac_length); string fine = hash_to_TOTP(out_hmac, out_hmac_length, digit); delete[] out_hmac; return fine; // Calculate TOTP according to RFC standard. } std::string TOTP::currentTOTP() { return GenerateTOTP(digit, refreshSeconds, algorithm, secret, getUnixTime()); } </code></pre> <img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=76104&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager"> Forum accounts are being connected to Johnny.Decimal accounts - Johnny.Decimal https://johnnydecimal.com/blog/0257-forum-account-connection/ 2026-10-18T06:21:07.000Z Johnny.Decimal <p>Until today, your forum account has been a completely separate account to your Johnny.Decimal account.</p> <p>This was confusing. People wonder why they needed <em>another</em> account for the forum.</p> <p>As of today, they're connected. When you log in at the forum, there's a button to do that <strong>With your Johnny.Decimal account</strong>.</p> <p>Existing forum logins will stop working in a month.</p> <p>There are more details in <a href="https://forum.johnnydecimal.com/t/the-forum-login-is-changing-to-your-johnny-decimal-account/2980">this pinned forum post</a>. There's a bit of a migration process if your email addresses don't match, sorry. If you have any problems, post in that thread or <a href="mailto:hello@johnnydecimal.com">email me</a>.</p> Digital recipe management for fastidious cooks - localghost https://localghost.dev/blog/digital-recipe-management-for-fastidious-cooks/ 2026-10-18T00:00:00.000Z Sophie Koonin <p>Much like your favourite recipe websites, I'm not going to get straight to the point, I'm going to start with a backstory and you're not getting a skip link.</p> <p>Having grown up with a dad who read cookbooks for leisure, and who caused me to turn vegetarian for several weeks once at the age of 13 when he presented me with a lamb heart stew for dinner, it was inevitable that I would be a foodie. Dad’s squid and red wine stew was my favourite dish as a child. He can't cook any more, but I have fond memories of those meals (even if I did eat as fast as I could so I could leave the table and go back on MSN) and I owe my inquisitive palate to his globetrotting home cooking. As middle-class Brits go, I’m as Waitrose as they come: say “Ottolenghi” three times into a Guardian tote bag and I’ll appear in a puff of sumac.</p> <p>These days, cooking for people is how I show love, which I definitely got from Dad. While the novelty's worn off for feeding myself and my husband (sorry James), I really enjoy having people over and putting on a spread (even if the kitchen then looks like a hurricane tore through it). Even at university, we used to hold parties in our student house where I'd cook for two solid days making sliders with homemade buns, big pots of chilli, clumsily-knotted pretzels, salads and cakes. Every Christmas I spend a weekend baking biscuits and sweets to post out to friends and family.</p> <p>I used to have a shelf full of cookbooks. Only instead of being lovingly creased and food-stained through use like my parents’ books are, mine sat on a shelf gathering dust, largely untouched, pages spotless and not at all stuck together. My problem is that I have very poor object permanence: if something’s not in immediate sight, I will forget it’s there. I couldn’t remember the recipes that I had in the books, or even that I <em>had</em> the books in the first place, so I never used them. (The same logic applies to the very old packets of various seasonings in the kitchen cupboards.)</p> <p>I’ve found the only way I reliably use recipes is if I have them available digitally. I’ve been collecting recipes from food blogs and recipe websites for a long time now - originally storing them in Evernote, which is what we did in the 2010s.</p> <p>And somehow, over the last decade, I’ve amassed over 5,000 recipes. Have I made all of them? Of course I haven’t. And there's definitely a few I come back to again and again. But it’s nice to know I have them in case I find myself in desperate need of a carrot cake recipe (or five).</p> <h2 id="paprika" tabindex="-1">Paprika</h2> <p>For the last 7 years or so I’ve been using <a href="https://www.paprikaapp.com/">Paprika 3</a> to manage my digital recipe collection. It’s a solid cross-platform app with cloud sync and a one-off cost per-platform rather than a subscription. I can clip recipes on my laptop, plan the next week's meals on my phone on the train, and I've got an old iPad sitting on the kitchen counter to view the recipe on while I'm cooking.</p> <p>All the recipe management apps I’ve tried have largely the same features:</p> <ul> <li>clip recipes from the web</li> <li>browse recipe websites from within the app, and download recipes</li> <li>create recipes from scratch</li> <li>scale and convert ingredient units</li> <li>tag recipes</li> <li>create meal plans</li> <li>create shopping lists from recipes</li> </ul> <p>I've categorised my recipes into what book they came from, different types of baked goods, different situations - for example, I've got a "quick weeknight dinners" category that's great if we just need something fast for dinner midweek.</p> <figure><picture><source type="image/webp" srcset="https://localghost.dev/img/n_sre3d4V0-280.webp 280w, https://localghost.dev/img/n_sre3d4V0-566.webp 566w" sizes="auto"><img loading="lazy" decoding="async" src="https://localghost.dev/img/n_sre3d4V0-280.jpeg" alt="A screenshot of some of the categories I've created in Paprika, laid out as a folder tree. There's Air Fryer, Baking, which has subcategories: Biscuits & cookies, Bread & rolls, Cake fillings & icings, Cakes, Crackers & savoury biscuits, Dough & pastry, Dumplings, Filled and flavoured breads, Flatbreads, Pastries & patisserie, Pizzas & tarts, Sweet breads & rolls, Sweet tarts & pies, Sweets, Traybakes, Vegan baking; Batch cook, BBQ, Books, which is cut off but you can see the first few - A Good Day To Bake, A Modern Way to Cook, Atsuko's Japanese Kitchen" class="small" width="566" height="1350" srcset="https://localghost.dev/img/n_sre3d4V0-280.jpeg 280w, https://localghost.dev/img/n_sre3d4V0-566.jpeg 566w" sizes="auto"></picture></figure> <h2 id="goldilocks-and-the-three-recipe-managers" tabindex="-1">Goldilocks and the three recipe managers</h2> <p>Paprika is a stalwart in the recipe app scene (and believe me, I’ve tried most of them), but it hadn’t been updated for years and I was getting a bit frustrated. It was <em>so</em> good, but lacked any kind of smart features - I was so bored of manually tagging recipes, and my extremely convoluted way of digitising recipe books and importing them into my collection was tedious as hell. My kingdom for literally any kind of OCR COME ON PEOPLE IT'S 2026. (Though while writing this I have just come across this <a href="https://github.com/IanDBallard/RecipeParser">Paprika Recipe Parser</a> tool which I’ll definitely try out.)</p> <p>Some newer competitors came on the scene post-2020, and offered some nice features Paprika didn’t have. <a href="https://pestlechef.app">Pestle</a> is a lovely-looking app which has really leant into the capabilities of Apple Intelligence, making importing super easy, and also supports importing from Instagram and TikTok; <a href="https://mela.recipes/">Mela</a> (by the same person who built <a href="https://reeder.app/">Reeder</a>) integrates with Apple Reminders and has a built-in RSS reader, which would be perfect for the food blogs I subscribe to. But I always found myself coming back to Paprika because other apps didn’t support nested recipe folders (which sounds incredibly nitpicky, but is a non-negotiable for me!)<a href="https://localghost.dev/blog/digital-recipe-management-for-fastidious-cooks/#footnote">*</a>.</p> <p>I mentioned I had an extremely convoluted way of importing recipes from recipe books to my Paprika collection. Well.</p> <p>If it’s a physical cookbook, I have to take photos of the pages, use Apple’s OCR in Preview to copy the text, then manually create the recipe in Paprika, which is so boring I rarely actually get round to it. If it’s an ebook, it’s a ridiculous workflow that I think I found on Reddit:</p> <ul> <li>import epub into <a href="https://calibre-ebook.com">Calibre</a></li> <li>convert the book to ZIP (an archive of HTML files)</li> <li>extract into a folder</li> <li>fix some of the garbled XHTML files that Calibre inevitably outputs</li> <li>run a local HTTP server in the folder</li> <li>open the IP address in Paprika’s in-app browser, and clip each recipe individually while half-watching ER (and I can't even use the "Download recipe" button because there are usually several recipes per outputted page)</li> </ul> <p>Given how boring that was to <em>read</em>, I'm sure you can guess how often I can be bothered to do that.</p> <p><small id="footnote">* If you're wondering why I don't just build one myself that does everything I want it to, the answer is that I have enough software maintenance to do in my day job, and my free time is for petting dogs </small></p> <h3 id="paprika-4-is-here-and-it-does-the-thing-now" tabindex="-1">Paprika 4 is here and it does the thing now</h3> <p>Great news for me: I happened to look at Paprika’s website yesterday and saw that they’d <a href="https://www.paprikaapp.com/news/2026/09/28/paprika-4-is-now-in-open-beta/">opened up the <strong>Paprika 4 beta</strong></a>, which supports - yesssss - <strong>recipe importing from photos</strong> and social media, recipe sharing, bulk categorisation, as well as being able to guess what categories you might want to add to a recipe! I’m extremely particular about the categories I want on my recipes, but also too lazy to scroll down a list and add them to recipes one by one, so this is a total game changer. (It is LLM-powered, so isn’t perfect - it keeps trying to categorise everything as being from “Dinner” by Meera Sodha - but I expect it’ll stop doing that eventually.)</p> <p>I tested it out by importing recipes from the <a href="https://farmerj.com">Farmer J</a> cookbook I’d picked up from a charity shop. It worked a treat! It’s basically completely shortcutted the workflow I had going before, and I don’t need to fill out any of the metadata except the category (which, as I mentioned, is super quick to do now).</p> <figure><picture><source type="image/webp" srcset="https://localghost.dev/img/vlCwcwW2qV-280.webp 280w, https://localghost.dev/img/vlCwcwW2qV-640.webp 640w, https://localghost.dev/img/vlCwcwW2qV-960.webp 960w" sizes="auto"><img loading="lazy" decoding="async" src="https://localghost.dev/img/vlCwcwW2qV-280.jpeg" alt="A screenshot of the final recipe that Paprika scanned in, cut off so you can't see the whole method. The title is 'Farmer J Mac' and there's a very enticing looking picture of golden baked mac and cheese with broccoli. It's clipped the timings for the recipe - prep 15 mins, cook 30 mins - and the number of servings (4). The method is a bit cut off on purpose but it says '1. Preheat the oven to 180°C fan (200°C/400°F). 2. Get your veg going. Chop whatever's in season and give it a good toss with olive oil, salt and pepper. Roast until golden and soft around the edges. Set aside. 3. Cook the pasta in a large pan of salted boiling water until al dente. Drain and set aside. 4. Make the béchamel. Melt the butter in a large pan, then add the flour and whisk for 2-3 minutes until smooth. Slowly pour in the warm milk, whisking'. It's clipped all the ingredients nicely: 400-500g seasonal veg (see facing page); Olive oil, for drizzling; 450g elbow macaroni or cavatappi; 2 tbsp unsalted butter; 2 tbsp plain flour; 1 litre whole milk, warmed; 100g extra mature Cheddar, grated;50g Parmesan, finely grated; Pinch of grated nutmeg (optional); Pinch of chilli flakes (optional); 100g mozzarella; grated Sea salt and black pepper." width="960" height="438" srcset="https://localghost.dev/img/vlCwcwW2qV-280.jpeg 280w, https://localghost.dev/img/vlCwcwW2qV-640.jpeg 640w, https://localghost.dev/img/vlCwcwW2qV-960.jpeg 960w" sizes="auto"></picture></figure> <p>Having switched to buying only epubs, I miss having a shelf full of cookbooks, so maybe I’ll start buying physical ones again if they're this simple to import now - I love it when I go to someone’s house and they have a copy of a cookbook I really like - or I can just screenshot ebook pages to import them, which is slightly less convenient but still way easier than the stupid dance I had to do before.</p> <p>Paprika 4 will be <a href="https://paprikaapp.zendesk.com/hc/en-us/articles/41887059110167-Will-Paprika-4-have-a-recurring-subscription-fee">moving to a subscription model</a>, which is unsurprising - the new features use LLMs, which aren't free. But it looks like existing users can keep using Paprika for free without the new features if they want.</p> <p>And if you ever need a good recipe, let me know - I've got a few.</p> Weeknotes W1 - James' Coffee Blog https://jamesg.blog/2026/10/18/weeknotes 2026-10-18T00:00:00.000Z James' Coffee Blog <p>Many of my pieces of writing, especially my creative non-fiction and Nature pieces, describe a single moment or the events that happened over the course of a day. With that in mind, one of the skills I want to develop in my writing is to consider longer periods of time in my writing – to tell stories that expand over greater lengths.</p> <p>During the <a href="https://indieweb.org/events/2026-10-14-hwc-asia-pacific">Homebrew Website Club Asia/Pacific meetup this week</a> – open to all, hosted at a time that works well in the Asia/Pacific timezone by <a href="https://burgeonlab.com">Naty</a> – the topic of weeknotes came up. This got me thinking. Could weeknotes be a way for me to think about a longer time horizon in my writing? Shortly thereafter, I decided I wanted to try weeknotes again, this time committing to writing one week note each week for four weeks, ideally on a Sunday evening.</p> <p>I suspect my weeknotes will be oriented more around bullet points than longer prose, but, in any case, I am coming at weeknotes afresh (<a href="https://jamesg.blog/weeknotes">I have tried to author weeknotes twice</a>, but on my last try I ended up spending more time making a custom page layout than writing, which may have made the practice less sustainable). I am keen to see what I write and share!</p> <h2 id="the-highlights">The highlights</h2> <p><em>Herein, events of the week.</em></p> <p>This was a busy week in terms of studying. I am continuing to work my way through the “art and the environment” block that I am studying. This week I spent a lot of time reading the textbook. I especially enjoyed learning about the Frost Fairs in London. Part of our work was focused on what we can learn about European attitudes to cold climates by analysing both art and prints from the London Frost Fairs as well as art and documents pertaining to the Arctic.</p> <p>We did a “virtual gallery visit” where one of our lecturers presented photos of and historical background about artefacts from the Uffizi Gallery in Florence, discussing them in the context of our module. This was my second time attending such a visit, and I got a lot out of it. I didn't realise the extent of the excess wealth the Medici family had.</p> <p>This was a busy week for events, too. I hosted a Homebrew Website Club (HWC) on Wednesday (<a href="https://indieweb.org/events/2026-10-14-hwc-europe">notes</a>), a HWC Writing discussion on Saturday (<a href="https://indieweb.org/events/2026-10-17-hwc-writing">notes</a>), and the 32-Bit Café Web Weaving Workshop today, as well as helping out with a non-technical event in a different community. Reflecting on these events in aggregate, they all have their own identity: I ask different opening questions in each, discussions flow in different ways. Indeed, when I am hosting an event I have to be “on” as much as possible; even if I take a few moments to find a link or write notes, I still need to be attentive to the wider room, thinking about how to make sure discussion continues between several participants. <em>Perhaps I should write something about hosting online events. Reader, what would you like to know?</em></p> <p>I had one day this week where I had <em>four</em> events I wanted to go to that were scheduled for the same three hour window: <a href="https://indieweb.org/Front_End_Study_Hall">Front End Study Hall</a>, the aforementioned virtual gallery visit, another university event, and a writing club event. It was hard to choose, but I decided to attend the first 30 mins of Front End Study Hall, which started before all the other events, then the full gallery visit. This worked out well: I had a great evening, and I didn't end up pushing myself to try and be in too many places at once.</p> <p>This afternoon I watched the last game in the NFL London series on the television. Stroud’s passes were amazing. The Jaguars had me on the edge of my seat many times due to flags (a problem in their game in London last week too). I missed the final minute, at which point the game was equal. I just read the final score and the <a href="https://www.skysports.com/nfl/news/13600610/nfl-london-games-2026-houston-texans-beat-jacksonville-jaguars-after-kaimi-fairbairns-walk-off-field-goal">Texans won 34-31</a>. I am not sure how many more games I will watch this season – the London games are on at such a convenient time – but I do want to learn more about how to “follow” a sport without watching the games. Any suggestions would be sincerely appreciated.</p> <h2 id="music-corner">Music corner</h2> <p><em>Herein, music I have enjoyed listening to this week.</em></p> <ul> <li>Courtney Barnett’s music is amazing. Thank you <a href="https://thamara.co.uk">Thamara</a> for the recommendation. I have listened to almost two whole album after learning about her music yesterday. Barnett is one of many Australian singers whose music I really appreciate, others being Hilltop Hoods, Montaigne, and Angus & Julia Stone.</li> <li>Taylor Swift released two new versions of Patient Zero: the acoustic and piano versions. Of the two, the piano version is my favourite. I shall have to listen to it again after finishing this post.</li> <li>I am on the lookout for hip-hop / rap bands, ideally that are more words-focused in their songs (and don’t sing too fast). If you have any recommendations, send me an email!</li> <li>I listened to a few songs by Sigur Rós this week whose music I loved. Any more recommendations along these lines would be sincerely appreciated!</li> </ul> <h2 id="thoughts,-wandering">Thoughts, wandering</h2> <p><em>Herein, wondering thoughts as-yet not explicitly included in my writing.</em></p> <ul> <li>How titles change a work.</li> <li>“Reading the texts of time.”</li> <li>I haven’t been doing many technical changes to my site lately. I haven’t had much inspiration for the coding side of my site of late. I feel both satisfied with the design of my website and also feeling like I want to make something new. Maybe a <a href="https://playground.jamesg.blog">new page in my playground</a>?</li> <li>I am interested in why bookshops are so fascinating to me even when I know I don’t want to buy any books because I have some to read already. I’m thinking of bookshops as a place for visual inspiration.</li> <li>I would like to make more zines, but I am also struggling to find the motivation. I saw a cool zine in a bookshop at the weekend that had a photo on the front cover and was tiny. I wonder if I could make a tiny photo zine?</li> <li>Blogging encourages writing to become part of life.</li> <li>I need new shoes for the winter. I always procrastinate on shoe shopping because I struggle to find shoes that are comfortable and that I like.</li> </ul> <h2 id="miscellanea">Miscellanea</h2> <ul> <li><a href="https://en.wikipedia.org/wiki/Santiago_Calatrava">Santiago Calatrava</a> has worked on many impressive buildings. Two that stood out that he has worked on are the <a href="https://en.wikipedia.org/wiki/Milwaukee_Art_Museum">Milwaukee Art Museum</a> and <a href="https://en.wikipedia.org/wiki/Li%C3%A8ge-Guillemins_railway_station">Liège-Guillemins railway station</a>.</li> <li>This series of Wonders of Web Weaving is coming to a close. I am not sure if there will be another series yet, but w will see! I will think more about that in the next year.</li> <li>I thought I had more links to share in this post, but I looked at my bookmarks and I realised I haven’t saved many. I should keep this in mind for next week!</li> <li><a href="https://burgeonlab.com/notes/2026/1017-2202/">Naty’s recent feed changes</a> caused some people to see all of her posts again in their web readers. This is common in tweaking web feeds. I have done the same in the past. I learned this week that Artemis was able to handle the changes with grace and didn’t show all of the posts in Naty’s feed as new. I can’t exactly remember all of the technical decisions I made to make this happen – it has been a while since I touched the polling part of the project – but I am glad to see things working.</li> <li><a href="https://www.bbc.co.uk/programmes/m0032jvl">The Book That Changed My Life</a> was a wonderful documentary. After the documentary I found myself thinking more about my favourite book, <a href="https://jamesg.blog/2026/01/15/walden">Walden</a>.</li> <li>Seeing <a href="https://joelchrono.xyz">Joel</a> and <a href="https://burgeonlab.com">Naty</a> publish weeknotes is what inspired me to give this a go. I have had fun! This is a different kind of writing from my other posts, but it’s nice to think through the week a little bit.</li> </ul> <script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a4ca43c56f2fab71',t:'MTc5MjM1NTA0Nw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script> <a class="tag" href="https://burgeonlab.com">Naty</a> <a class="tag" href="https://burgeonlab.com/notes/2026/1017-2202/">Naty’s recent feed changes</a> <a class="tag" href="https://en.wikipedia.org/wiki/Li%C3%A8ge-Guillemins_railway_station">Liège-Guillemins railway station</a> <a class="tag" href="https://en.wikipedia.org/wiki/Milwaukee_Art_Museum">Milwaukee Art Museum</a> <a class="tag" href="https://en.wikipedia.org/wiki/Santiago_Calatrava">Santiago Calatrava</a> <a class="tag" href="https://indieweb.org/Front_End_Study_Hall">Front End Study Hall</a> <a class="tag" href="https://indieweb.org/events/2026-10-14-hwc-asia-pacific">Homebrew Website Club Asia/Pacific meetup this week</a> <a class="tag" href="https://indieweb.org/events/2026-10-14-hwc-europe">notes</a> <a class="tag" href="https://indieweb.org/events/2026-10-17-hwc-writing">notes</a> <a class="tag" href="https://jamesg.blog/2026/01/15/walden">Walden</a> <a class="tag" href="https://jamesg.blog/weeknotes">I have tried to author weeknotes twice</a> <a class="tag" href="https://joelchrono.xyz">Joel</a> <a class="tag" href="https://playground.jamesg.blog">new page in my playground</a> <a class="tag" href="https://thamara.co.uk">Thamara</a> <a class="tag" href="https://www.bbc.co.uk/programmes/m0032jvl">The Book That Changed My Life</a> <a class="tag" href="https://www.skysports.com/nfl/news/13600610/nfl-london-games-2026-houston-texans-beat-jacksonville-jaguars-after-kaimi-fairbairns-walk-off-field-goal">Texans won 34-31</a> Why I'm rebuilding my IndieWeb projects with Claude - Articles by Aaron Parecki https://aaronparecki.com/2026/10/17/5/rebuilding-my-indieweb-projects 2026-10-17T14:46:17.000Z Aaron Parecki <p>I recently came across <a href="https://brennan.day/the-indieweb-now-has-genai-and-claude-built-in-what-do-we-do/">Brennan's post</a> noticing that Claude Code has been showing up in the commit history of a bunch of my IndieWeb projects lately. That's true! I was wondering when someone would notice. I haven't been hiding it, but I also haven't written anything about why I'm doing it, so this seemed like a good time to finally get my thoughts down.</p> <h2>The principles are about what you own</h2> <p>Brennan's post summarizes the IndieWeb as:</p> <blockquote> <p>the main idea being to empower individuals to own their own identity, data, and web presence rather than relying on centralized social media silos</p> </blockquote> <p>That's a pretty good summary. But notice that no part of it talks about what tools you use, or what you use to build your tools. That was a very intentional part of the <a href="https://indieweb.org/principles">IndieWeb principles</a>, which start with "Own your domain and your data." The principles are about owning your data and being able to choose where your data is hosted, not about how the code behind it was created. It's not even about everyone hosting their website from a server in their closet, although if you want to do that you definitely should!</p> <h2>These projects were old</h2> <p>I launched some of these tools literally 15 years ago. The two big ones for me are webmention.io and IndieAuth.com. Both are old Ruby codebases that use long-abandoned ORMs and ancient versions of Ruby.</p> <p>Rewriting these had to happen at some point regardless. Frankly they are a security nightmare waiting to happen. If I hadn't done the rewrites now, the realistic alternative would have been to just shut down the services.</p> <p>And IndieAuth.com has a particularly awkward history. Around 2016-2017 I realized it was too confusing to have a service called IndieAuth.com that actually did two separate things. It was an authorization server that let you sign in to IndieAuth apps with your domain (via an account like GitHub), and it was also a way for developers to add "sign in with your domain" to their own web apps. So I officially decided to split those into separate products. That's where <a href="https://indielogin.com">indielogin.com</a> came from, which launched in 2018. IndieLogin gives app developers a way to add "web sign-in" to their apps without having to implement RelMeAuth or the IndieAuth spec themselves. But I never got around to splitting out the other half, the authorization server that your website links to as its IndieAuth server, and issues tokens for Micropub apps.</p> <p>Finally thanks to developing a style of working with Claude Code that I'm comfortable with, I was able to launch <a href="https://indiekey.id">IndieKey</a>. This is the replacement for the other half of indieauth.com. It has a bunch of features I'm excited about, too much for this blog post, but finally I am comfortable migrating people over from indieauth.com to this. Keep an eye out in the coming months for an automatic migration, which Claude has been very helpful in planning.</p> <h2>Modularity, demonstrated</h2> <p>One of my favorite principles is <a href="https://indieweb.org/modularity">modularity</a>:</p> <blockquote> <p>The more your code is modular and composed of pieces you can swap out, the less dependent you are on a particular device, UI, templating language, API, backend language, storage model, database, platform.</p> </blockquote> <p>The webmention.io rewrite is a pretty good demonstration of this. I was able to move webmention.io from the Ruby code to PHP without anybody who uses it needing to change anything on their end. That's the whole point of building things on open protocols. The implementation behind the endpoint can change completely and the rest of the web doesn't have to care.</p> <h2>Single point of Aaron</h2> <p>Brennan links to the wiki page <a href="https://indieweb.org/single_point_of_Aaron">single point of Aaron</a>, which, yes, I know. It's been a running joke (and a real concern) for a long time.</p> <p>I run these services for the community because I want to show what's possible. I never wanted them to be seen as the only option. I've wanted people to build alternatives to webmention.io and IndieAuth.com for years, and I'm always glad to see a blog platform build in Webmention support natively instead of relying on my service.</p> <p>So if you don't like that I used Claude to help build the replacement, that's fine! You can treat it as though I shut down the service and go find an alternative, because that is what would have happened anyway. I fully admit I knew some people would be unhappy with my choice of tools. But honestly, that's great, because it might encourage someone to build alternatives to these services, which is a win for the community overall. In fact at least one has already shown up as an alternative to webmention.io: <a href="https://codeberg.org/eltrac/weepinbell">weepinbell</a> as a direct response to my rewrite.</p> <p>That's <a href="https://indieweb.org/pluralism">pluralism</a> working the way it's supposed to. Hopefully this pushes more people to build their own tools and services, especially if they're opposed to the way I work.</p> <h2>Understanding matters more than the tools</h2> <p>Linus Torvalds had <a href="https://lore.kernel.org/lkml/CAHk-=whTs09_ozN+e09GU68N1wPP56MUzDjrg9rnKxQUa0A_4Q@mail.gmail.com/">a good comment</a> on the Linux kernel mailing list about people using these tools in kernel development:</p> <blockquote> <p>The kind of expectations <em>I</em> have is that people do their best and I expect people to understand what they are doing.</p> <p>But that understanding has very little to do with what tools they use.</p> <p>And quite honestly, in my experience, the people I respect and call intelligent are not the ones that shy away from using new and interesting tools.</p> </blockquote> <p>That matches how I think about it. I wrote many of the specs these services implement, and I still read and understand what gets shipped. Claude is doing the typing, not deciding how Webmention works.</p> <h2>Have fun</h2> <p>The last (but not least) IndieWeb principle is <a href="https://indieweb.org/fun">have fun</a>.</p> <p>The code was never the interesting part for me. I like thinking about things from the protocol and product perspective. Maintaining a large codebase is not fun for me. But I do like building things and making useful tools. I like figuring out how building blocks can compose into a larger useful product.</p> <p>And now it's a lot more fun, because I get to focus on the product and design of these tools instead of getting stuck in the weeds of the code. I've shipped more improvements to these projects in the last couple of months than I had in the previous few years.</p> <ul> <li><a href="https://indiekey.id">IndieKey</a> - An IndieAuth server you can use for your website, built from scratch in the last month.</li> <li><a href="https://webmention.io">Webmention.io</a> - Receive webmentions for your website, forward them to webhooks, or fetch from the API. A complete rewrite of the old Ruby app that is now much more maintainable.</li> <li><a href="https://meetable.org">Meetable</a> - The events platform that runs <a href="https://events.indieweb.org">events.indieweb.org</a>, which I started developing in 2019. Recently I was able to ship a bunch of features on the todo list backlog: <a href="https://aaronparecki.com/2026/10/14/6/meetable-proposed-events">Proposed events</a>, <a href="https://aaronparecki.com/2025/11/25/5/meetable-release-notes-november-2025">recurring events</a>, <a href="https://github.com/aaronpk/Meetable/pull/212">code of conduct confirmation</a>, a <a href="https://events.indieweb.org/2026">calendar heatmap</a>, and many more!</li> <li><a href="https://indieauth.rocks/">IndieAuth.rocks</a> - An IndieAuth spec validator. This has been on my todo list for literal years!</li> <li><a href="https://quill.p3k.app/">Quill</a> - A Micropub client for posting notes, photos, articles and more, rewritten from scratch with a significantly improved UI!</li> <li><a href="https://news.indieweb.org/">IndieNews</a> - I added an admin UI to manage block lists to deal with the influx of poorly written LLM posts that were being submitted.</li> <li><a href="https://micropub.rocks/">micropub.rocks</a> and <a href="https://websub.rocks/">websub.rocks</a> - Turns out the email login forms were being abused to send spam, so I replaced it with passkey login.</li> </ul> <h2>Disclosure</h2> <p>While I don't work at Anthropic, I have worked with some folks there on launching <a href="https://aaronparecki.com/2025/11/25/1/mcp-authorization-spec-update">Enterprise-Managed Auth</a> in Claude.ai.</p> <p>And yes I used Claude to help me draft this blog post, with a healthy amount of hand editing afterwards.</p> <h2>Anyway</h2> <p>The one nit I will pick with Brennan's post is the title: "The IndieWeb Now Has genAI and Claude Built-in". Yes, many of the IndieWeb services I run have now had contributions from Claude. But the IndieWeb is not the services I run. The IndieWeb is a community of people, and a wide variety of tools and services based on a shared set of principles.</p> <p>I don't expect this to change everyone's mind, and that's okay. People can reasonably draw their lines in different places. <a href="https://indieweb.org/pluralism">Pluralism</a> means we can use different tools built different ways, but still interoperate. If you've got thoughts, write a post on your own site and send me a Webmention. It'll get to me, through the brand new PHP version of <a href="https//webmention.io">webmention.io</a>.</p> Book Review: Are You *Really* The Doctor? by Matthew Hutchinson ★★★⯪☆ - Terence Eden’s Blog https://shkspr.mobi/blog/?p=76754 2026-10-17T11:34:57.000Z Terence Eden’s Blog <img src="https://shkspr.mobi/blog/wp-content/uploads/2026/10/are-you-really-the-doctor.avif" alt="Book cover featuring a pair of crossed plasters in a dark brown colour." width="200" class="alignleft"> <p>A few months ago, I went to see <a href="https://www.bbc.co.uk/programmes/m002vbxx">Dr Hutchinson record his stand-up comedy special for the BBC</a> - it's about his experiences working in the NHS as a Black doctor. As the title of the book implies, some of the public can be a mite suspicious that anyone with even a hint of melanin can rise beyond being a porter or, at a push, a nurse.</p> <p>Much like <a href="https://shkspr.mobi/blog/2019/01/book-review-this-is-going-to-hurt/">Adam Kay's "This Is Going To Hurt"</a>, this is part biography, part rant about the NHS, and part humorous look at what it takes to be a modern doctor. Hutchinson's book has rather less gallows humour and rather more racism.</p> <p>The problems of racial inequality in the NHS aren't just focussed on patients; they're also reflected in the way staff are treated. Rather than just recounting all the abuse he's been subject to, the book takes a good look at the actual statistics. Of course, this makes for slightly grim reading at times, so the frequent injections of humour are most welcome.</p> <p>The UK quite often seems in the shadow of larger cultures. As the book points out:</p> <blockquote><p>This same issue is understudied in the UK – to the point where the absence of research is glaring. While we are clearly not just a little America, we aren’t so different that we can be confident we’re not replicating the same here.</p></blockquote> <p>Because of that, at times the book does feel a little bit like the "<a href="https://knowyourmeme.com/memes/we-have-food-at-home">we have [racism] at home</a>" meme.</p> <p>There's an almost relentlessly cheery irreverence to some of the issues - but what else can you do? Sometimes it takes a good dose of comedy to cut through the bleakness. There's a slight streak of ageism within the book - especially when it comes to older doctors trying to use new technology. Although, to be fair, that was also my experience when working at NHSX. There are some people within the system who are desperate for it to remain preserved in aspic as even minor improvements are a threat to their position in the hierarchy.</p> <p>A minor grumble, the problem I have with books like this - and with <a href="https://shkspr.mobi/blog/2019/05/review-the-secret-barrister/">The Secret Barrister</a> - is that a lot of the moaning about how hard it is to become a professional doctor / lawyer just generates a giant shrug from me. Every piece of medical media in the last 50 years talks about how bone-crunchingly hard it is. All I can think of is "none of this should be coming as a surprise to you!" Should it be easier (and less sleep depriving) to be a doctor? Sure! But given it isn't, perhaps dial down on the clichés of how uniquely awful your <em>chosen</em> career is.</p> <p>The book isn't just a list of complaints, of course, everything is backed up with statistics (although unreferenced). Thankfully, the book ends with some practical suggestions of how the NHS can improve. It would certainly be interesting to read a version of this from 2046 to see how much has changed - given the improvements already bearing fruit, I'd hope that the UK health service would become much less racist over time.</p> <img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=76754&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager"> 2026-10-17 11:37: We had a Hotpoint engineer come out to repair our washing machine yesterday. While replacing... - Kev Quirk https://kevquirk.com/2026-10-17-1137 2026-10-17T10:37:00.000Z Kev Quirk <p>We had a Hotpoint engineer come out to repair our washing machine yesterday. While replacing the machine, he forgot to connect the waste pipe and we came down to this mess this morning. 😡</p> <video src="https://kevquirk.com/content/images/2026-10-17-1137/1000012490.mp4" controls width="100%" height="500px" preload="metadata"></video> <div class="email-hidden"> <hr /> <p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p> <p>You can <a href="mailto:19gy@qrk.one?subject=2026-10-17%2011%3A37">reply to this post by email</a>, or <a href="https://kevquirk.com/2026-10-17-1137#comments">leave a comment</a>.</p> </div> Weeknote #2022 - Robb Knight • Posts • Atom Feed https://rknight.me/blog/weeknote-2022/ 2026-10-17T06:12:00.000Z Robb Knight <p><a href="https://lexontech.org/x-is-bad-though">X is bad</a>. Obviously.</p> <p><a href="https://social.lol/@daveycraney/117432170563880917">Davey hits the nail on the head here</a>:</p> <blockquote> <p>People return to X just want followers in the strictest sense of the word. Sycophants that will just click like and subscribe on their posts without calling them out on anything. Much like the companies they cover, they just want to see number go up.</p> </blockquote> <p>Couple of interesting game projects. The first, <a href="https://github.com/snuri00/ps2-web-recomp">PS2 games in the browser with WebAssembly</a>. Secondly, someone <a href="https://miyoo-n64.pages.dev">ported a bunch of N64 games to Miyoo Mini</a> and a there was a<a href="https://github.com/cacuracaptors/mk64-miyoomini">second project just for Mario Kart</a> released around the same time. I'm going to have some fun with these.</p> <p><a href="https://www.youtube.com/watch?v=ppnhwS-LcAI">This video about sketching</a> was interesting even if it is trying to sell a course which, as best I can tell, everyone doing art on YouTube is.</p> <p><a href="https://nothing.tech/products/cmf-speaker-m?Color=Dark+Grey">CMFs new speakers</a> look great — I'm sad I have no use for such a thing.</p> <p><a href="https://www.converse.com/uk/en/products/all/collections/converse-x-hello-kitty">Converse have a new Hello Kitty range</a> and I want them all.</p> <p>Donald Faison jumped did an impromptu rendition of "Everything comes down to poo" in <a href="https://www.youtube.com/watch?v=uIdGoo9IStY">this interview</a>.</p> <p>Matt of Unch fame <a href="https://www.wyrd.systems/posts/unch-money-2025-2026">wrote up the financials</a> for a year of running a cryptic crossword magazine (of which I've bought each issue even though I do not enjoy such things I've since learnt). Postage to anywhere outside the UK as usual becomes the most expensive thing to handle.</p> <p><a href="https://www.openculture.com/2026/10/a-900-page-pre-pantone-guide-to-color-from-1692.html">A 1692 guide to colour</a>. This is cool.</p> <p>I was looking at buying another pink AL Star (I did of course, vibrant pink to be specific) but I wanted to see how the colour compared to the other pink Safaris and AL Stars I had. <a href="https://inksea.pl/lamy-colours-comparisons/">This comparison</a> was the most complete list I could find.</p> <p>Two HTML boilerplate posts to keep for reference — one from <a href="https://vale.rocks/posts/html-boilerplate">Vale</a> and one from <a href="https://www.matuzo.at/blog/2026/html-boilerplate">Manuel</a>.</p> <p><a href="https://ahatem.github.io/IoskeleyMono/#download">Ioskeley Mono</a> is a "<em>monospace font crafted to match Berkeley Mono's aesthetic. Built by configuring <a href="https://github.com/be5invis/Iosevka">Iosevka</a></em>". I've switched to this everywhere I can.</p> <p>Bunny have <a href="https://bunny.net/blog/deploy-static-sites-anywhere-with-the-bunny-net-cli/">updated their CLI for better deployments of static sites</a>. Nice.</p> <p><a href="https://tinylittleoffice.com">Tiny Little Office</a> is the kind of stuff we need more. No logins, no bullshit.</p> <p>These <a href="https://cultpens.com/collections/yup">pencil cases by Yup!</a> are incredible and I want them all.</p> <figure><img src="https://cdn.rknight.me/site/2026/yup-food-pencil-cases.jpg" alt="A table will pencil cases on it but they all look like food or condiments" /></figure> Autumn - James' Coffee Blog https://jamesg.blog/2026/10/17/autumn 2026-10-17T00:00:00.000Z James' Coffee Blog <p><em>The night-given crystalline coating on the red leaf shimmers with the burgeoning light of day. As I take a step forward, the light hits the ice crystals in a different way. We had our first frost last night.</em></p> <p>I looked up to see an expansive winter-blue sky, with faint lavender on one side of the sky and the beginning of a yellow glow on the other. Day was about to break, but the sun had not yet risen.</p> <p>Next to the red leaf that caught my eye there was neater red leaf, this one with veins made more definite by the frost; the fiery-red of the leaf became white. Around me, the occasional rabbit hopped over the path; birds sang. A peaceful whisper permeated the air reminding me of the forthcoming season. I came outside to feel the cold; to experience the latter part of autumn.</p> <p><em>An evergreen tree is tipped with silver, the colour of the frost accentuating the droop in the leaves of the tree, almost as if the tree itself was being weighed down by the frost.</em></p> <p>My morning was full of observations of the season. Two young deer stood with their parent, all grazing on a frosty field. A low white haze blanketed a field that was home to many sheep. A bird skimmed across the river. Heavy trees hid an abandoned, cobbled house. Shortly thereafter, the sky became more yellow. <em>The sun is beginning to rise.</em> Birds sat on a tree and caught the rising sun. I love watching the light change. Trees became golden.</p> <p style="text-align: center;">⁂ ⁂ ⁂</p> <p>Should there be any riches in the world, may they be Nature and friendship and warm coffee on a cool day. Nature is among my closest companions, there whenever I look out the window or step outdoors, existing always in memory and in the present. Even on a busy street, the odd leaf rests on the pavement.</p> <p>While I gazed out the window drinking a warm cup of coffee – around which I cupped by hands to savour all the warmth I could – I smiled at a passer-by, who smiled back. I love moments like this. Shortly thereafter, a lady passed by with a suitcase, to which was affixed a sticker that said “HOPE” with an accompanying illustration.</p> <p style="text-align: center;">⁂ ⁂ ⁂</p> <p><em>Winter forces me to confront limits — of how hard it is to stay in cold for long. What keeps me going is the beauty of Nature. There are things I can only feel in Winter; there are things I can only see in Winter. The grass twinkles with the frost. The pulse of the song. What is the pulse of Nature?</em></p> <p style="text-align: center;">⁂ ⁂ ⁂</p> <p>As day continued, warmth interleaved with the cool air; the breeze was cool but the sun continued to shine down, creating conditions where it was pleasant enough to sit outside and watch the world go by in the park for a while. I thought about the fleeting nature of autumn while gazing at the trees and watching as people walked past. I wanted to look at the trees as much as I could so as to reinforce my impression of the colours; of how autumn transforms this place. I could see there were fewer leaves on the trees than in previous weeks, but the colours were as joyful as ever.</p> <p>I take notes, holding onto some thoughts, while also letting some thoughts come and go, knowing that, as with the passage of seasons, I cannot rush my thoughts forward. I sat looking around at the world, seeing what I could see; appreciating the afternoon.</p> <script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a4c036ee091434ab',t:'MTc5MjI0OTY2Mw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>