Latest Posts (20 found)

Passing of the torch

If you are subscribed to People and Blogs, you might have noticed that today’s newsletter arrived from a different address. That’s because the always lovely Zach has officially become the new custodian of this series. The peopleandblogs.com domain name has been transferred, the mailing list has been migrated (from Buttondown to Buttondown), and the RSS feed has been redirected. As I wrote in a previous post , I’m gonna publish three more interviews here on the site before officially saying goodbye to the series on July 10th. But contrary to what I wrote months ago, I decided that I’m not gonna keep the interviews archived here on the blog, and instead I’ll redirect them all to their new location. Keeping them here would be obviously good for me, it’s extra traffic that comes to the site, but I don’t care about traffic, and I much prefer to send people towards Zach’s site and help the series grow that way. I’m very happy that the series will continue on, and I’m excited to see where Zach will take it. As I said to him, this is his series now, he can and should do whatever he wants with it, and I look forward to seeing it evolve over the next months and years. Thank you for keeping RSS alive. You're awesome. Email me :: Sign my guestbook :: Support for 1$/month :: See my generous supporters :: Subscribe to People and Blogs

0 views

📝 2026-06-19 12:25: Little chicks are starting to venture out from under mum. 🐥

Little chicks are starting to venture out from under mum. 🐥 Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️ You can reply to this post by email , or leave a comment .

0 views

Proud Dad Moment

Yesterday was sports day at my kids' school, and usually it consists of us standing in a field, being baked by the sun, waiting for our kids to come on and do their couple races each. All in all, I'm only ever interested in a couple minutes of the 2.5 hours we stand there. Usually my oldest doesn't try that hard as he struggles with resilience. So if he's not clearly winning, he won't push, he'll give up. And our younger son was always a little too young and therefore uncoordinated, and usually at the back. This year was different. Our youngest tried really hard and was rapid ! He ended up winning 2 of his races and coming second in another. Great result. But the stand out was our oldest son. At the end of the day, they give out all the awards and our son won the prized sportsperson of the year award. Not the day …the year . The headteacher talked in great depth about how he is always helpful to the younger kids, how he's always a good sportsman, even if he loses, and how he's happy to share his knowledge to help others be better. This would make most parents proud, right? But for us, even more so. Our kids are adopted, and thanks to a significant amount of early neglect, our oldest has always found it impossible to share and help others. He always put himself first. That's not because he's selfish. He's actually a very kind, loving boy. It's because in those early years he had to survive and in order for him to survive it was literally him versus his siblings. What a horrendous situation to be in. Anyway, to hear that he's not only been a good sport throughout the year, but also that he's sharing and working with his teammates filled his mum and I with joy and made us so proud. My wife shed a little tear - she thinks I didn't notice, but I did. Me being the clown that I am, I shouted "WELL DONE SAUSAGE!" at the top of my voice so the whole school could hear. Everyone knows I call them the sausages so this made sure every single person on that playground saw him have his moment. What a legend. ❤️ Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️ You can reply to this post by email , or leave a comment .

0 views

Edoardo Baldi

This week on the People and Blogs series we have an interview with Edoardo Baldi, whose blog can be found at edoardob.blog . Tired of RSS? Read this in your browser or sign up for the newsletter . People and Blogs is supported by the "One a Month" club members. If you enjoy P&B, consider becoming one for as little as 1 dollar a month. Hello! I’m Edoardo, in my thirties, born near Milan (Italy) and raised in the Alps of the same region, to escape the boredom of too flat a horizon. I studied physics, first in Milan, then abroad in Switzerland, where I spent a little over four years on a PhD that convinced me academic research wasn’t for me – or so I thought, since I didn’t stray too far. In the following years I became a “research software engineer”, meaning a software developer who works closely with research. It took me a while to realize that, despite the many benefits, that work had become a routine I was taking too much for granted. Or better: I had lost sight of why I was staying there; why I kept choosing that configuration for my life. Now I’m trying to figure out if teaching the two subjects I’m most passionate about – math and physics – is what I want to do in the next chapter of my career. I can never get enough of hiking in the mountains, especially over multiple days – as long as my body agrees. And sharing an experience with other people who love the same thing is my ideal vacation. Books, writing – I don’t know how many experiments with novels and short stories I’ve done over the years – and puzzles of all kinds (including programming challenges, even though I’m a particularly slow coder) are some of the activities that can easily fill my free time. Having always loved tinkering with computers, I think I started writing random things online quite early. If I remember correctly, it was on LiveJournal or MySpace, prehistoric stuff now. I discovered WordPress during high school, following a guy from my same school who wrote ironic essays on philosophy topics. I tried to emulate that model, but I didn’t get very far as it wasn’t my thing. Years later, with some friends fond of cinema, again on WordPress, I started a collective blog where we wrote our opinions on the movies we watched, often together. The name of the blog – Sweet Sue and Her Society Syncopators – was a tribute to a classic 50s American comedy. (I’ll let you work that one out.) During my PhD, I collaborated on and managed the university cinema club’s blog. At the time, however, I also started publishing my very personal ideas on books and movies on another blog, whose name or domain I honestly don’t even remember now. I think I tried to recover something from that blog via the Wayback Machine, with no success. Fast-forward several years, I realized why none of those blogs had survived: I was writing on commission – I loved the perk of press screenings, but writing something afterwards was non-negotiable. Or I was performing for some imagined audience by covering whatever was trending, not what I actually cared about. I could say that my personal blog was born when I decided that my online space would be only a public personal journal: the only rule was to write about what interested me the most, in the way that felt most natural. This is still the reason behind my current blog. How long is it going to survive? I don’t know. It did well, so far, with ups and downs. Beyond my hiking recaps, almost everything I write starts from curiosity – a science-based question (“if I ate an apple a day for a year, how many kg of peel could I accumulate?”), something I want to understand well enough to explain, a brain teaser that sometimes keeps me awake. Since it’s often something I don’t know, a research phase almost always follows – and I admit that, sometimes, it derails my intention to write. I keep a dedicated note for each idea, where I track its evolution. When I feel like I’ve reached a conclusion of sorts, I then sketch out a structure and use it as a guide for the first draft. Curiously, all my notes are in English, but the first draft of anything I write is always in Italian. Then I translate into English, and very often rewrite some parts that don’t flow very well in the other language. And yes, I often use Claude for a final proofread: I’ve given it strict instructions on what it can and can’t touch, and how. The content is always mine, and I’m careful to keep it that way: I don’t want to end up with a voice I no longer recognize as my own. As for the tools, my personal notes live in an Obsidian vault – because they must be plain text files – and I write all my drafts almost exclusively in iA Writer. It’s been my first choice for many writing projects, at least in their early stages. One feature I particularly love is its support for authorship , without violating the plain text pact. When I sit down to write the first draft, I have only one need: to be alone in a fairly quiet environment. Honestly, I’ve never tried writing in a public place, like a café – and the few times I did write on a train, it was surely due to a deadline I couldn’t avoid. As far as I’m concerned, it’s more the act of moving through space that stimulates what I might call creative thinking – which I take to mean authentic rather than original , as in “totally new”. And I’m also convinced that the environment influences my creativity, but I couldn’t say how or why. Often I’ve only realized much later that I had visited an environment from which I returned with ideas I considered creative – whether these didn’t go very far is another, unresolved story. I think I’ve tried dozens of frameworks to create a blog, starting with the large family of static-site generators. After several attempts, intrigued by some input from Manu, I gave Kirby a chance and discovered that it met all my needs. One above all: my blog’s content must be in plain text, as I don’t want to deal with any kind of problem taking it with me, wherever it might be in the future. So, for the moment: Kirby CMS, hosted on a fairly basic server managed by Hetzner. The domain is registered on Porkbun, and the DNS is managed by Cloudflare. I’ve also written a dozen custom plugins to tweak many aspects of my website because, for me, tinkering with the mechanics of a personal blog is part of the joy of having one. I just can’t resist – and I keep telling myself “tinker less, write more”. I would probably study web design and web technologies properly from the start – I mostly stumbled into this stuff through my day job. I say this to avoid having to settle for some preconfigured service that isn’t right for me. I would love to have a domain like , but the problem isn’t availability so much as the popularity of my name. And, honestly, I’m not ready to pay $200 a year for a personal website. The maintenance costs for my blog are quite low: 4€ and something a month for the server, plus the annual cost of the domain – about 20€. Kirby CMS requires a one-time license (100€, renewed every four years), and this is the only expense I periodically re-evaluate: the moment it no longer aligns with my needs, I will have no problem planning a migration elsewhere. In fact, I’ve already done it several times as a stress test , but for now I don’t feel the need to. My website generates no revenue, nor have I ever tried to make it do so. Personally, I have nothing against monetising a personal website, provided it’s done honestly. If I were to do it, I probably wouldn’t rely on platforms like Substack – only because I like building things myself. Even today I financially support some blogs because I believe in the work of the people behind them – or to give a friend a small nudge to keep going. A good part of the blogs I follow, or like to return to from time to time, I discovered thanks to “People & Blogs” – or through “Ye Olde Blogroll” . I think it’s unlikely that anyone reading this page doesn’t know either of them; but if that’s the case, I invite you to take a look, exploring even the older, less obvious stuff. I want to mention a friend’s project, halfway between a personal blog and a photography portfolio, that I had the pleasure of contributing to . I’m very fond of it: partly for my friendship with the author, and partly because it circles a theme that has quietly followed me for years: the sense of belonging to a place, or to multiple places; the idea, the concept, the experience of what we call home . The project is “Stay Stay Stay” by Elettra Pistoni: if you’re not into reading about this topic, her pictures are well worth a look. I also think she would more than gladly welcome the opportunity for this interview, but I’ll leave the decision to those in charge. I’ve lost count of how many newsletters or feeds I’ve subscribed to over the years, and it doesn’t really matter. I’ve reached the point where the list of online content I follow consistently has no more than ten items. Among these, two blogs and a newsletter (in Italian) that I return to quite regularly, even to reread older things: I’ll take this as a cue to share a bit of what’s going through my head – two thoughts and a side project that will maybe see the light someday. Finally, a heartfelt thanks to Manu for offering me the opportunity to share a bit of myself with this community! Now that you're done reading the interview, go check the blog and subscribe to the RSS feed . If you're looking for more content, go read one of the previous 146 interviews . People and Blogs is possible because kind people support it. “Useful Fictions” by Cate Hall Julia Evans ’s blog, a trove for tech enthusiasts The newsletter “It’s Friday I’m (not) in love” , partly inspired by “Modern Love”, the New York Times’ well-known column. Whenever I feel like telling someone “I don’t have time”, I stop and remind myself that it’s almost never true. In fact, never. It’s just my fear of making a commitment, or a lack of courage to admit what I really care about. I try never to hide behind this excuse with the people I really care about, because they don’t deserve it. I’ve also written a short post about it . This could be one of my guiding tenets , because I haven’t been able to refute it yet: “Actions, not words, reveal our real values” . It’s not mine , and I often struggle to accept it myself. But I’m convinced that if we actually lived by it, we would have far more genuine and satisfying relationships with other people – in whatever sense you want to take that. Being a hiker obsessed with traveling light, I started working on an app (web only to begin with) that lets me keep track of my gear and which items I decide to bring on each trip. Dozens of these tools already exist, but this is my vision of what I’d want such an app to do. I called it “Baseweight”, and I hope to have an alpha version out in the near future. If someone is curious, the app’s future home will be at baseweight.my . And if you’d like to share your thoughts on it, don’t hesitate to reach out ! Opinions and suggestions are especially welcome at this early stage.

0 views

Do not bargain to be loved

A gentler world begins in the way you touch your heart. Be soft with the light inside you. Caress your body with this breath. God is nothing else but the place where the sun comes up in your chest. You are the glimmering destination. You are the golden honey daubed on the bread of the ordinary. Whatever is perfect, whatever is heavenly, begins here. — Fred LaMotte Do not bargain to be loved. Do not negotiate. When love is withheld as a punishment, as a manipulation, as a means to move you in a certain direction: Do the worst and most difficult thing and quit asking for it. Withdraw your hand, put it in your pocket. Clamp your mouth shut, let your silence swell, do not ask for explanations. It's already been explained. Love is not contractual. Love does not have terms you must fulfill before you get to have it. Love exists and is made apparent in all situations where it is present. If it is not apparent — if you cannot feel it, hear it, and see it in action — it is not present. This seems like a harsh rule but it is the only rule of love. Love is not confusing. Love is clear. Love is simple. Love is obvious. Big as the sky, sturdy as a mountain. Brave and honest, tender and unrelenting. You don't have to poke around in dark corners asking, Is it here? Is it here? You don't have to dig for love until your fingers bleed. You don't have take apart some sharp-edged thing to get at the gooey love-filled center. Love doesn't hide. Love appears and stays. Love is present. When you're loved, you know it. You feel it. It opens you up. It blesses you with spaciousness and closeness, with freedom and safety, equal measures. You don't have to choose one and lose the other. Love does not offer you a half. Love is the whole. Do not bargain to be loved. Here are some things that are not love: Compliments Love may express itself in those ways. Love may give you affection, attention, all of the above. Wonderful. Love can bring you these things, but it does not hold a monopoly. Agreement can come from avoidance of conflict. Attention can come from jealousy. Affection can come from loneliness. Compliments can come from a need to please. Gifts can come from guilt. Love is not transactional. Love is not a handful of coins in your pocket, spend one here, spend one there, save some up for a rainy day. Love does not run out. Love is self-created, self-fulfilling, endless supply. Love is active generosity. Love is splendid, exorbitant kindness. Love cannot be measured or doled out in small bits, cut into smaller slices. When someone tries to love you this way, here is the explanation (take a deep breath): What they offer you is not love. They offer you something , to be sure. But it is not love. If love is what you want, don't bargain for what is not love. Some people want to love but don't know how. Or they want to get love, but don't know how to give it. You don't teach them by accepting not-love and pretending it is love. You can show them by knowing what love is and being it, best as you can: Being clear, being simple, being obvious. Not accepting half-truths or hiding. Not equating affection with love, apologies with love, attention with love. Not being pulled into transactions. Not being backed into a corner. Not making yourself smaller. Not agreeing when you don't agree. Not tolerating what you shouldn't tolerate. Clear, simple, obvious. Big and sturdy. Brave and honest, tender and unrelenting. Even when saying goodbye. Compliments

0 views

Datasette Apps: Host custom HTML applications inside Datasette

Today we launched a new plugin for Datasette, datasette-apps , with this launch announcement post on the Datasette project blog. That post has the what , but I'm going to expand on that a little bit here to provide the why . Datasette Apps are self-contained HTML+JavaScript applications that run in a tightly constrained sandbox hosted on your Datasette application. They can use JavaScript to run read-only SQL queries against data in Datasette, and can run write queries too if you configure them with some stored queries . Here's a very simple example and a more complex custom timeline example - the latter looks like this: Apps are allowed to run JavaScript and render HTML and CSS. They are limited in terms of access - the they run in prevents them from accessing cookies or localStorage and they also have an injected CSP header (thanks to this research ) which prevents them from making HTTP requests to outside hosts, preventing a malicious or buggy app from exfiltrating private data. Datasette Apps started out as my attempt at building a Claude Artifacts mechanism for Datasette Agent , but I quickly realised that the sandboxed pattern is interesting for way more than just adding custom apps to the interface surface and promoted it to its own top-level concept within the Datasette ecosystem. They're also a fun way to turn my multi-year experiment in vibe-coded HTML tools into a core feature of my main project! You can try out Datasette Apps by signing in with GitHub to the agent.datasette.io demo instance. Since the very first release, Datasette has offered a flexible backend for creating custom HTML apps via its JSON API. One of my earliest Datasette projects was an internal search engine for documentation when I worked at Eventbrite - it worked by importing documents from different systems into SQLite on a cron and then serving them through a Datasette instance with a custom HTML+JavaScript search interface that directly queried the Datasette API. I had client-side JavaScript constructing SQL queries, which originally was intended as an engineering joke but turned out to be a really productive way of iterating on the app! That project, combined with my experience building my HTML tools collection and my experiments with Claude Artifacts , has convinced me that adding a Datasette-style backend to a self-contained HTML frontend is an astonishingly powerful combination. Imagine how much more useful Claude Artifacts could be if they had access to a persistent relational database. That's what I'm building with Datasette Apps! Here are a few of the ideas and patterns I've figured out building this which I think have staying power. This is the magic combination that makes Datasette Apps feasible in the first place. I need to run untrusted HTML and JavaScript on a highly sensitive domain - an authenticated Datasette instance can contain all sorts of private data. The attribute lets me run that untrusted code in a way that cannot interact with the parent application - it can't read the DOM, or access cookies, or steal secrets from . It can however use and friends to load content (or exfiltrate data) from other domains. But... it turns out if you start an HTML page with a header you can set additional policies that lock down access to other domains. I was worried that malicious JavaScript would be able to update or remove that header but it turns out that doesn't work - once set, the CSP policy is immutable for the content of that frame. Having locked down those iframes to the point that they couldn't do anything interesting at all, the challenge was to open them back again such that they could run an allow-list of operations, starting with read-only SQL queries against specified databases. I built the first version of this with , which allows a child iframe to send messages to the parent window. I created a simple protocol for requesting that the parent run a SQL query - the parent could then verify it was against an allow-listed database before executing it. One of the LLM tools, I think it was GPT-5.5, suggested that on its own can be exploited if the iframe somehow loads additional code from an untrusted domain. I don't think that applies to Datasette Apps, but I also believe in defense in depth, so I had GPT-5.5 help me port to a MessageChannel() based transport instead. has the advantage that if a page navigates to somewhere else the channel closes automatically, removing any chance of executing commands sent from an untrusted external page. If you navigate to the timeline demo and search for the string you'll pull in some search results that embed images from the domain. This domain is not in the CSP allow-list, so it trips an error. Those errors are captured and transmitted back to the parent frame, where they can be displayed in a useful error log. This is meant to make hacking on apps more productive by surfacing otherwise-invisible problems. I built an experiment demonstrating that you can even turn this into a one-click-to-allow mechanism for building the CSP allow-list based on what breaks, but I haven't integrated that idea into just yet. SQL queries are also visibly logged - scroll to the bottom of the timeline page to see that in action. I want apps to be able to conditionally write to the database, but this is an even more dangerous proposition than SQL reads! My solution involves Datasette's stored queries feature, rebranded from "canned queries" and given a major upgrade in the recent Datasette 1.0a31 - work that was directly inspired by Datasette Apps. Users can create a stored write query that performs an insert or update, then allow-list that specific query for an app to use. Usage from code inside an app looks like this: I'm only just beginning to explore the possibilities this unlocks myself, but my goal is to support full read-write applications built safely as Datasette Apps. The Datasette Apps plugin has no dependency on LLMs at all, but these self-contained apps are the perfect shape to be written by a modern LLM. The create app form includes a copyable prompt at the end. This prompt has everything a model needs to know to build a new app, including the schema of any selected databases. This means you can click "copy", paste it into ChatGPT or Claude or Gemini, tell it what you need, and there's a good chance the model will spit out the code necessary to build the app. If you have Datasette Agent installed your AI assistant will also gain tools to both create new apps and edit existing ones, Claude Artifacts style. Datasette Apps started life back in April as datasette-agent-artifacts , a plugin I have since renamed to keeping only its editing tools . I built that as one of the first plugins for Datasette Agent , to help get the plugin hooks into the right shape. That first prototype was mainly built using Claude Opus 4.6 in Claude Code. When I switched track to Datasette Apps I started with a plan constructed using Codex Desktop and GPT-5.5 xhigh, based on extensive dialog and feeding in both and other prototypes I had built. Most of the work that followed stuck with Codex, but in the few short days that we had access to Claude Fable 5 I had it run a security evaluation of the product (an ability that would get it banned by the US government shortly afterwards) and it found a very real problem. I was allowing users to allow-list CSP hosts for their apps, but Fable pointed out the following attack: That's clearly unacceptable. I fixed it by restricting the ability to allow-list any domain to a new permission, which is intended just for trusted staff. Site administrators can also configure Datasette with a list of , which regular users can then select. This means you can do things like allow and your users will be able to build apps that load extra JavaScript libraries from the cdnjs CDN. I've reviewed Datasette Apps extremely closely, especially the security-adjacent parts of it. The critical sandbox and CSP configuration are based on multiple AI-assisted prototypes and tests. I'm really pleased with this initial release. Datasette is growing beyond its origins as an application for serving read-only data into a much richer ecosystem of tools for doing useful things with that data once it has been collected. Datasette's roots are in data journalism. I've always been interested in the question of what comes next after a journalist gets their hands on a giant dump of data about the world. Datasette supports exploring and publishing it. Datasette Agent adds interrogating it with AI assistance. Now Datasette Apps expands that to building custom interfaces and visualizations to help unlock the stories that are hidden within. You are only seeing the long-form articles from my blog. Subscribe to /atom/everything/ to get all of my posts, or take a look at my other subscription options . A less privileged user with permission creates an app that queries SQLite for all available tables and selects and exfiltrates all of the data to a host they had allow-listed via CSP. They then trick an administrator user with access to private data into visiting their app. ... and the app can now run queries as that user and steal their private data!

0 views

Going bla bla bla about wtf

I had a natter with David Meyer about the past fortnight in UK tech policy drama. We did this deliberately as a casual chat, as opposed to a techlaw deep dive, so don’t expect anything too heavy. (I had in fact planned to switch off my brain this summer like normal policy wonks do. So […]

0 views

Decoupling from the web

I spent a lot of time recently reflecting on the things that make me happy and unhappy. And one thing that has emerged from all this meandering inside the inner workings of my brain is that the web is making me unhappy. The web, as a whole, is a big place and as Bo said «Anything that brain of yours can think of can be found» which is both a blessing and a curse. Because even though my content diet is quite strict—compared to most people at least—I’m still fucked by the fact that I am a curious person and there’s an infinite amount of interesting things to be found out there on the web. The problem is that there’s also an infinite amount of depressing and/or enraging shit out there on the web, and even though I’m not on any social media platform of any kind, I’m still exposed to that crap. And I’m tired of that. Which is why I’m wondering if it’s possible to completely decouple from the web. I need to be “on the web” for work, since I code sites for a living, and so quitting the web entirely is not really an option at the moment. But consuming content? That is not something I have to do. And nobody is forcing me to do so. Spending more time paying attention to the way my body feels made me realize how much I neglected taking care of my mind recently. And that’s clearly not good since those two things go hand in hand, «mens sana in corpore sano» and all that. And so I might actually try “quit” the web as a source of content and see what happens. I suspect I might end up reading more books, which is good since the goal was to read at least 36 of them this year, and I’m currently 115 pages into number 25. Am I going to miss out on a lot of stuff? It’s possible. But aren’t we all constantly missing out on a lot of stuff anyway? Wish me luck. Thank you for keeping RSS alive. You're awesome. Email me :: Sign my guestbook :: Support for 1$/month :: See my generous supporters :: Subscribe to People and Blogs

0 views

‘Popa’ Botnet Linked to Publicly-Traded Israeli Firm

For the past four years, a sprawling Android-based botnet called Popa has forced millions of consumer TV boxes to relay Internet traffic linked to advertising fraud, account takeovers, and mass data-scraping efforts. This week, researchers from multiple security firms concluded that the Popa botnet is linked to NetNut , a “residential proxy” provider operated by the publicly-traded Israeli firm Alarum Technologies Ltd [NASDAQ: ALAR]. Malicious streaming devices sold online that enroll the user’s home Internet address in a residential proxy service. Image: HUMAN Security. Popa is a massive botnet, but by all accounts it is unlike traditional botnets that enlist compromised systems in destructive activities, such as coordinating huge distributed denial-of-service attacks. Rather, Popa appears designed with a singular purpose: Implementing a persistent communications layer capable of registering a device, maintaining long-lived encrypted connections, and opening communication tunnels on demand. Experts say Popa is a plugin component associated with the Vo1d botnet, a large-scale malware campaign targeting unofficial Android-based TV boxes. These devices, which are marketed under thousands of brand names and model numbers and broadly available for purchase at top e-commerce destinations, all advertise the ability to stream hundreds of subscription video services for an up front one-time fee. But as the FBI and security industry experts have warned repeatedly, these streaming boxes typically bundle or come pre-installed with software that turns the user’s TV into a “ residential proxy ” — allowing anyone to route their Internet traffic through that device for as long as it remains plugged into a wall socket and connected to a local network. More concerning, some of these proxy networks do little to stop malicious customers from communicating with and even compromising systems on the local network of the unsuspecting device owner. The first clues about Popa’s origins came in a 2025 report from the Chinese security company XLAB , which flagged at least nine domain names that were used to register and direct the activities of compromised devices. In a report released today, the security firm Qurium described how it stumbled on some of those same domains while investigating a series of disruptive and expensive data scraping events targeting the company’s hosted organizations in May 2026, in which the scraping activity was scattered evenly across more than 1.4 million Internet addresses. Qurium said it found several dozen domains used to control Popa that were all hosted in lockstep across multiple Internet addresses over time, including gmslb[.]net , safernetwork[.]io, tera-home[.]com, and ninjatech[.]io . Digging deeper, Qurium discovered gmslb[.]net was referenced in dozens of pirated or modded video content streaming apps, such as CRICFy , DooFlix , Sprozfy , RTS Tv , Flixoid , CyberFlix , Rapid Streamz , TvMob and HD/OceanStreams . Qurium’s report notes that most of the domains long used to control the Popa botnet were seized or dismantled in July 2025 , after Google , HUMAN Security and Trend Micro teamed up to disrupt Badbox 2.0 , a botnet that is closely associated with Vo1d. Qurium said that immediately after that disruption, several dozen new domains were registered to serve as controllers for the Popa botnet, but that one of those control domains was not new: ninjatech[.]io . Ninjatech is a company founded by Moishi Kramer , whose LinkedIn profile says he is vice president of research and development at NetNut. That resume credits Kramer for helping NetNut to build from the “ground up,” “designing the architecture,” and “scaling the NetNut” before the company was acquired by Alarum Technologies. A self-created listing at the job board F6S references Kramer as the sole owner of the Ninjatech domain (a screen capture of it is pictured below). Image: F6S.com. Responding via email, Mr. Kramer said Ninjatech ceased operations approximately five years ago, when the company sold a software development kit (SDK) called Popa that was designed to use a small portion of a device’s bandwidth and to run only after the host application obtained user consent. “That code was sold and licensed to third parties including resellers years ago,” Kramer said. “Once software is distributed that way, the original developer has no control over how others later modify, rebrand, or deploy it.” Kramer said neither he nor NetNut builds, operates or maintains the infrastructure being described as Popa, nor does he control the Ninjatech domain. “I didn’t register the June 2025 domains you mention, and I don’t know who did,” he continued. “I have no control over, or visibility into, that infrastructure. I can only tell you it isn’t operated by me or by NetNut.” But in a separate Popa research report released today, the proxy-tracking company Synthient said a recent analysis of the Popa SDK revealed outbound traffic clearly associated with NetNut. “The research team assesses with high confidence that devices running Popa forward traffic from Netnut clients,” Synthient wrote. “This proves without a shadow of a doubt that Popa actively continues to be used by NetNut as part of their proxy pool.” Synthient’s platform receiving outbound traffic from Popa. Image: Synthient.com. Alarum Technologies, NetNut’s Tel Aviv-based parent company, said the reports by Synthient and Qurium contained “demonstrably inaccurate assertions and flawed deductions rather than verified facts.” Alarum shared a statement saying they reject the basic characterization of the SDKs and technologies discussed in the reports as a “botnet.” “The SDKs at issue are designed to facilitate bandwidth-sharing functionality and do not transform user devices into malware-controlled systems or otherwise compromise the devices on which they operate,” the statement reads. “Netnut operates a commercial proxy network and maintains policies, procedures, and technological measures designed to promote lawful and responsible use of its services.” Alarum said NetNut places “significant emphasis on appropriate notice and consent mechanisms, conducts customer due diligence, monitors for potential misuse, and takes steps intended to detect and mitigate suspicious or unauthorized activity.” “This method of operation is supported both by internal procedures and policies, including performing KYC checks and additional due diligence of NetNut’s customers, as well as employing various technological measures, designed to assist in identifying and addressing suspected misuse of the network,” their statement continued. However, in a report released on June 8, the proxy tracking service Spur asserted that NetNut does not require corporate verification or meaningful “know your customer” procedures before allowing customers to purchase proxy access. “An individual can sign up, pay, and route traffic through partner address space, including space belonging to institutions whose users never opted in,” Spur wrote . “The ‘verified corporations only’ claim is simply marketing for bandwidth sellers, not an access control on who actually uses the proxies.” “Nor is NetNut the only front door,” Spur continued. “A number of downstream white labelers and resellers repackage the same ISP proxy pool under their own brands. These outlets typically perform no KYC at all, less scrutiny than NetNut itself, who at the very least might assign an account manager to potential users. Anyone who knows where to look can buy access through a reseller with nothing more than a burner email address and $5 in crypto.” Synthient found that although the most recent builds of Popa (as of three months ago) have added the ability to ask the user for consent before installing proxy components, not all variants or previous versions of Popa contain this functionality. “Of the over 20 genuine Popa publishers analyzed, none of them were observed asking for user consent,” Sythient wrote. Chris Formosa is senior lead information security engineer for Black Lotus Labs , a division of the Internet backbone carrier Lumen Technologies . “What especially makes Popa dangerous is just how widely used NetNut is for reselling and sharing,” Formosa said, explaining that many other proxy services simply resell NetNut proxies rather than building out their own far-flung proxy networks. “So these Popa IPs appear in tons of different services all over the ecosystem, which makes it one of the most problematic and dangerous proxy botnets on the market currently.” Formosa said the Popa botnet averages between 1.5 million to 2.5 million distinct IP addresses each day, relying on between 250 and 300 Internet addresses that are used to direct its activities. “That’s why Popa is so dangerous,” Formosa said. “It may not be the largest botnet we have seen, but it is spread all over the industry, making its power very amplified.” Formosa said while that makes Popa one of the larger botnets out there today, its numbers pale in comparison to those previously boasted by IPIDEA , a China-based proxy provider that until recently operated a daily pool of nearly 10 million devices that they resold as proxies to anyone. In January 2026, Synthient published research showing that multiple new large DDoS botnets had grown rapidly by tunneling through IPIDEA proxies into the local networks of unsuspecting TV box owners and infecting other Android-based devices behind the user’s firewall. IPIDEA is based largely on SDKs used to view pirated streaming content on a vast number of TV box devices, but the service’s numbers have dwindled since January, when Google and industry partners took legal action to seize domain names that IPIDEA used to control devices and proxy traffic through them. Jérôme Meyer , a security researcher at Nokia Deepfield , said the total population of devices participating in the Popa botnet may be far higher than Lumen’s estimates. Meyer told KrebsOnSecurity that Nokia is monitoring 26 of at least 359 known relay nodes for the botnet, and estimates that each relay node handles between 35,000 and 60,000 clients simultaneously. “On the relay node subset I am looking at (26 of them), 750,000 unique sources in 24 hours,” Meyer wrote in response to questions. Nokia Deepfield released its own report today on RoboVPN , a VPN app tied to the Vo1d botnet’s Popa plugin that Qurium attributes to NetNut/Alarum Technologies. Experts say many of the world’s largest proxy providers have updated their public-facing branding to highlight their utility for training AI platforms, implying it is a primary use case for their residential proxies. That’s because AI services tend to rely on constantly mass-scraping the Internet for new text, images and video content that can be used to train large language models (LLMs). NetNut and other proxy services have recast themselves as critical infrastructure for the AI scraping economy. Image: Synthient.com. “AI companies depend on web-scraped content: for pre-training, for retrieval, for agent grounding, for search,” reads a report this month from Include Security that examines the prevalence of proxy SDKs in smart TV apps. “But the modern web isn’t scrapeable from a datacenter. Cloudflare, DataDome, HUMAN, among others throttle or block requests from known cloud IPs. The workaround is residential proxies. A scraping job routed through a Comcast or T-Mobile subscriber’s connection arrives at the target site from an IP that belongs to a paying residential customer.” This non-stop content scraping has spawned more than 70 copyright infringement lawsuits against major tech companies that have acknowledged large-scale data scraping as a major source of the “brains” behind their commercial AI offerings. Ironically, much of that scraping is being aided by proxy services that are intimately tied to unofficial Android TV boxes and associated SDKs whose stated purpose is streaming pirated content. The scraping activity has become so aggressive that it often overwhelms the targeted websites, preventing them from being reachable by legitimate visitors. In many reported cases, nonprofit organizations, libraries and universities have complained of constantly battling to keep their services online in the face of relentless data-scraping firms hiding behind residential proxy services. A survey conducted last year by the Confederation of Open Access Repositories (COAR) found while some content scraping bots are rather innocuous, “others are sufficiently aggressive that they are increasingly causing service disruptions in repositories and other scholarly communications infrastructures.” More than 90 percent of survey respondents indicated their repository is encountering aggressive bots, usually more than once a week, and often leading to slow downs and service outages. “Automated web scraping is nothing new, and has been the key technology underlying search engines such as Google for over 30 years,” wrote Brendan O’Connell , platform manager at the Directory of Open Access Journals (DOAJ), a free, community-curated index of peer-reviewed academic journals. “However, the current investor-fueled AI startup craze means there are now thousands of well-funded companies developing and deploying their own scraping tools to train AI models, alongside existing major players like OpenAI and Google.” Across the United States, local communities are pushing back against the proliferation of new data centers aimed primarily at improving the capabilities of AI. But security experts say the general public remains largely unaware that using one of these unsanctioned Android TV boxes means their “smart TV” is almost certainly using a significant amount of bandwidth each month to help train modern AI models. Even households without these sketchy TV boxes can still have their smart TVs turned into residential proxy nodes, just by downloading one of thousands of apps made available on Samsung and LG smart TVs. Spur said it recently scraped the LG and Samsung app stores and found that each had approximately 3,000 apps available for download. Many of these apps are simple games or utilities that state in the fine print that the user’s Internet connection will be used to download data and that they can opt out at any time. Spur said it found that  more than 42 percent of apps available for download via the webOS operating system on LG smart TVs include SDKs that turn one’s television into an always-on residential proxy node. More than a quarter of the apps made for Samsung’s Tizen operating system had similar residential proxy components, Spur found. Image: Spur.us. Experts say it’s questionable whether TV apps with proxy SDKs can obtain meaningful consent from users for installing an always-on proxy connection, particularly when anyone in a household — including children — can effectively opt the family TV into a residential proxy network just by installing a simple game or app. “Privacy-policy disclosure is the wrong control surface for a TV,” Include Security wrote. “It is hard to scroll through a legal document navigated by arrow keys on a remote, and the in-app consent dialog doesn’t convey that a paying customer is about to route their scraping traffic through the user’s home internet.” Spur’s head of research Sean Simmons told KrebsOnSecurity that most people do not have a working mental model for what it means to sell access to their residential IP address, no matter what device they are using. “And on a TV, the gap is even wider,” Simmons said. “A one-time prompt navigated with a remote can disappear into the setup flow, while the app keeps monetizing the connection long after anyone remembers what they accepted.” Simmons said LG and Samsung should follow the lead of other TV platforms that have already drawn a line against residential proxy providers, pointing to policies by Amazon that prohibit apps facilitating proxy services for third parties. Likewise the TV streaming device maker Roku reportedly now bars developers from using proxy SDKs and has removed apps that bundled them. Piracy related apps pushing proxy SDKs onto unconsenting users. Image: Synthient. Apps that turn one’s device into a residential proxy node are not limited to smart TVs and no-name streaming boxes, of course. As noted by the security firm Infoblox , mobile app developers can embed SDKs provided by the residential proxy networks into their products to monetize their software, allowing them to receive a small amount of money on each installation. The result, Infoblox said, is that devices are frequently enrolled without the owner’s knowledge, typically through free applications such as VPNs, streaming apps, screensavers and “productivity” apps such as PDF viewers and break reminders. All too often, these proxy services are beaconing out from employee devices brought into the workplace, Infoblox found. In a blog post earlier this month, Infoblox said it discovered that fully 65% of its customer base was querying one or more residential proxy related domains. “We saw steady growth in these queries in 2025, with a 25% increase over the year to over 500 billion per month,” Infoblox wrote . “Over 90% of our pharmaceutical and food & beverage customers have queried residential proxy indicators. Perhaps even more concerning is that over 60% of government and banking customers have as well.” Infoblox researchers Nick Sundvall and David Brunsdon warned that with residential proxies in the corporate environment, external access is granted to an organization’s IP space. “If threat actors were to abuse the residential proxy to attack a third party, the third party’s incident response would, correctly, identify your residential proxy as the source,” they wrote. “Untangling that, by proving that you were the conduit and not the threat actor, costs time, creates legal exposure, and can damage your reputation. The stunning prevalence of these services within customer environments warrants attention from both network defenders and policy makers who should consider how the risks posed by residential proxies could be impacting their security posture.”

0 views
Unsung Yesterday

Show your hands honor for the strange power they bring you

Here’s a big interactive essay I just finished . The theme: What does it take to build interfaces that truly allow for fast operation – and why that matters. If you like the interactive details posts here on Unsung, the essay is kind of a concentrated dose of all that. You can technically read it on the phone, but it’s so much better on a computer (or a big tablet). It has ~40 interactive playgrounds, and sounds, and a glossary, and all sorts of fun stuff I’m doing for the first time. I wanted to share some things I learned over the years, and nod toward mostly anonymous creators of UX inventions I’ve long admired. I also thought it could be interesting to make interfaces appear as machinery – you’ll see what I mean. Let me know if I succeeded! #flow #interface design #marcin wichary

0 views
Stratechery Yesterday

An Interview with Michael Morton About E-Commerce in the Age of AI

An interview with Michael Morton about e-commerce and AI, including the challenges of unfalsifiable bear cases, distribution versus referal models, grocery, and autonomous vehicles.

0 views
Brain Baking Yesterday

The Panini Sticker World Cup Fever Strikes Again

With the 2026 FIFA World Cup well on its way, the Panini sticker fever has been raging through nearby playgrounds and homes alike. The 2026 edition might be a little bit special as it was recently revealed that Panini lost the exclusive rights. After fifty years of faithful partnership, FIFA moves the deal to Panini’s biggest competitor: the American Topps (owned by Fanatics). The 2030 World Cup sticker book will be Panini’s last FIFA-related book you can try to fill. And perhaps that is a good thing? Local newspaper Het Nieuwsblad estimated that in order to complete your sticker book, statistically speaking you’ll need to buy around stickers—totalling to the hefty sum of . I never realised that filling your sticker book could be that expensive! That’s even more expensive than your average Magic: the Gathering modern deck— and that hobby can be expensive . Considering most feverish collectors are youngsters in primary school, it might even be called outrageous. For the previous World Cup, this would be roughly . Is has never been as expensive as now. Why? Panini cites The Usual Suspects: rising manufacturing and shipping costs. I don’t entirely buy that. My own little investigation, comparing previous Panini stickers I still had lying around, yield another nasty surprise: not only has the cost gone up, but the quality has gone down as well. My Aladdin Panini stickers I collected in the nineties had a nice gloss finishing that resists scratches. That finishing is gone now, but the biggest change is the sticker size. A quick dimension comparison (measured in centimetres): In 30 years, Panini stickers have shrunk in size by almost . The reasoning behind this is due to the massive team size of the World Cup, having so many stickers would otherwise cause the sticker book to weigh as much as a heavy textbook. So this “shrinkflation” effect is disguised as a way to protect our children’s backs. Clever. My notebook, scattered with World Cup 2026 stickers. Left: local ads from Euro 2020. Top right: Aladdin stickers with yellow border for comparison; a full centimetre taller. Another aspect of the nineties stickers I miss is the variability of them. In my Aladdin album, I sometimes could paste in just half of an image. A scenery from the animated movie, such as the Genie in a parade swirling around with fire-lit batons as depicted in the sticker of the photo above, would be split into two stickers, making it extra satisfying to “complete” just that one scene instead of the entire book (which I never bothered to do or didn’t manage to, I can’t remember how I felt about it). In addition, some of the stickers depicted just the characters in a translucent cut-out shape. I found these stickers to be more fun and desirable to paste in compared to the standard shaped ones that came with a yellow border. Of course, comparing a whimsical Disney animated film to a national football team where you just have to paste in every team member according to their position on the field diminishes the creative options Panini has to play around with the setting. To me, the FIFA stickers have always been one of the more boring sets. Perhaps the contract is not a big loss, although financially speaking, given the typical World Cup craze, I bet it is. According to another local news article , Panini’s expected turnover for this World Cup would be in the billions in euro. Yet this FIFA deal loss is one of the many losses: no more UEFA Champions League stickers, no more European Championship, and now also no more World Cup. In USA, they also lost the rights to print NBA and NFL stickers. There are rumours of yet another complete Panini sellout because of all this. The article also mentions the interesting history of the Italian company: in the nineties it was even briefly sold to comic giant Marvel Entertainment! Did you know there are Sonic sticker collections ? Super Mario Ones? Hot Wheels? L.O.L. Surprises? Harry Potter, Jurassic Parc, Toy Story 5, Stitch, Tour De France, Darts, Frozen, Spider Man, … You name it, they have it. Did you also know the second hand market is cutthroat when it comes to unopened vintage card packs? As I wrote before , this really does feel like unopened Magic: the Gathering booster boxes… If you want to complete your collection but can’t because of limited local trading opportunities, there’s also the option to buy singles directly from Panini. They know fans want a complete sticker album, so expect to drop more for specific requests. The best strategy? Wait until the World Cup fever passes and then buy everything. The interviewee from Het Nieuwsblad managed to procure all FIFA Euro 2024 stickers for just . Good luck with the sticker hunt. Don’t forget to play fair: never trade two-for-one! Related topics: / collecting / By Wouter Groeneveld on 18 June 2026.  Reply via email .

0 views
Unsung Yesterday

“Every pigment in this catalogue has a paper trail.”

Today at Unsung, three efforts with perhaps thought-provoking depth. The first one: a new website called Storied Colors . = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/every-pigment-in-this-catalogue-has-a-paper-trail/1.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/every-pigment-in-this-catalogue-has-a-paper-trail/1.1600w.avif" type="image/avif"> It’s a… catalogue of [two hundred and fifty] named colors — pigments, dyes, lakes, glazes, and a small number of digital hues — each accompanied by the documentary evidence required to call it by its name. I wouldn’t normally link to this, as this feels closer to graphic design than UX design, even if the typography of the site is pretty exquisite, and the history of some colors truly fascinating. What particularly stood out to me about the site that felt worth celebrating was its rigor ; there are a lot of cheap color tools and some great ones , but this approaches the subject matter with a different kind of energy: There are good color dictionaries. There are good histories of paint. There are excellent technical references on conservation chemistry. What is harder to find is one place where the chemical formula, the workshop floor, the trade route, the patent dispute, and the eventual ban all sit on the same page — sourced, dated, and free of the gloss that surrounds color writing online. Most of what you can read about historical color on the web has been rewritten three or four times from the same Wikipedia paragraph, with the citations dropped along the way. What you are reading here is an attempt to put the citations back. There’s also this… The corpus is curated, not comprehensive. There are perhaps a thousand pigments worth knowing about; the launch corpus selects two hundred and fifty whose stories are best documented, most consequential, or most strange. The catalogue is actively expanded; new entries land regularly. Editorial discipline is what keeps the standard honest. …buyoed by clean information architecture with tags and deep search. I’d love to see more of that applied to UX. (You might remember that I missed it in the review of the Laws of UX book , which feels on the surface like roughly a similar idea.) Equally importantly, however, for Color Stories, none of this stands in the way of some beautiful writing : This is not a forgotten oddity. This is mid-twentieth-century American consumer culture casually serving food on uranium-glazed plates for thirty-five years across two production runs, marketed as everyday tableware to ordinary households, and discontinued only when the second uranium supply ran out. The plates sit in display cabinets across the country, in good condition, still glowing faintly under a Geiger counter. Kudos to the (anonymous) creator. #above and beyond #colors #web

0 views
annie's blog Yesterday

This is it

As long as you keep secrets and suppress information, you are fundamentally at war with yourself…The critical issue is allowing yourself to know what you know. That takes an enormous amount of courage. ― Bessel A. van der Kolk What we live through, what we experience, how we navigate a life that is one  unknown  after another, how we keep breathing in the midst of pain, how we learn to carry suffering, how we open our arms to each other, how we offer comfort in the face of tragedy: none of it really makes sense. How we look forward with hope, how we keep functioning without hope, what we do when it feels like there’s nothing to hope for, when meaning is lost, when it would feel nice to have the earth open and swallow us whole… How we find  small things  to delight in, how we notice a good thing in the middle of a shitstorm, how we put our heads down and plod forward through despair, how we tilt our faces toward the sun, how we park the car and get out and shut the door and check the mail and walk inside when our minds can’t imagine why we’re doing any of it and our hearts are howling, screaming, shattering… How we make art , how certain things become sharper, how we accept one another’s discomfort, how we make room for each other’s pain, how we read a poem or a comic or watch a show or stare out the window, how one story might pull us under but another story might be what saves us… Bukowski  said,  What matters most is how well you walk through the fire , and what we didn’t realize is that it’s all fire, all the time, and how we walk through it is how we live, how we keep living, because love is a fire, love is as strong as death which means sometimes, a lot of times, we live through things that seem likely to kill us. The mystery is you and how you are here, right now, slamming your hand in frustration, yelling, cursing, sobbing, retreating into silence, considering violence, burdened with helplessness, pacing and exhausted, uncertain and trembling, numb with detachment, shaking with anger, frozen in shock, shaking with  grief,  panicking, breathless. It’s extraordinary — the way  you  breathe, the way you keep breathing. The way you question yourself, the way you smile, the way you let tears roll down your face, how you peer through the flames to see colors and light.

0 views

.gitignore Isn’t the Only Way To Ignore Files in Git

I’ve been using Git for so long and I just realized you can ignore files at three different levels and not just with . The three files you can use to ignore files are: is the usual file where you write files you want to ignore. It’s checked into Git along with the rest of the code. Whatever files you add to it will not get taken into account when running commands. The file lives in the directory of every Git repository but changes to it are not checked into Git. It usually has a few comment lines on a fresh Git repository. This file is useful for ignoring things on a per-repo basis. For example, you may have a personal file in a repository that you don’t want to check into git but you also don’t want to add to because it’s unique to your workflow. In that case you would add to . The file lives in your machine’s home directory in . Whatever filenames are added to this file are ignored globally at a machine-level. This file is not checked into Git and isn’t associated with any particular repository. It’s a great place to add files that you want to ignore in every git repository on your computer. For example, if you’re on macOS, adding here would be ideal. You can customize the global ignore file to be a different file. For example, if you want your global git ignore file to be you would run the command: And if you ever want to return to the default setting, run: When adding filenames to any of these, you can use this command to check how a filename is being ignored. For example, if you want to check how is being ignored, run in any Git repository. Here is the output when the repository’s is ignoring : Here is the output when the repository’s is ignoring : Here is the output when the global file is ignoring : And here is the output when a custom global ignore file is ignoring : If there is nothing ignoring a file, the command produces no output.

0 views

Studium Emacs

In 2019, I started using DOOM emacs as my main emacs “distribution”. A decision which I figured I’d stick with for many years to come. In late 2023, I switched back to neovim for some time , and finally came back to the light early last year . However, we all knew this day would come. I have been bitten by the vanilla emacs bug, the call to craft my own lisp environment being too loud to ignore any longer. After some polishing work, I am content with introducing: Studium Emacs . After building out a ~2200 line literate DOOM configuration , I felt it was time to declare emacs bankruptcy and move to a configuration in which I understood everything that was going on. I’m not going to talk badly about Doom emacs, I believe it is really good - and suggest people that are starting with emacs to use it if they’re coming from vim/neovim because they can immediately be productive. I also like the leader key, and have adopted it for some of what I am doing, but I also think that vanilla keybinds are better in many respects (especially with a programmable keyboard ). I also had been using evil mode pretty extensively for editing text, so modal editing is another aspect I stole for Studium Emacs. With that being said, stock Emacs has come a long way since those days in 2018-19 which merited an emacs “distribution”. Eglot is built in, use-package is a first class citizen, as is treesitter and various modes that were not present 5 years ago. In fact, this journey has surprised me in that so much is right there for you. Over the past ~6 months or so as I prepared to jump off the deep end, I had also been using the built in keybinds more and more, first with org-mode’s built ins, and then moving to more file management and generic keybinds, to the point that I would say navigationally, I use mostly emacs keys, and meow is a great addition to the standard emacs keybinds, falling back gracefully to native binds. My main problem with DOOM is that is obfuscates much of the working system under helper macros and stuff that is now unnecessary with the release of Emacs 31 on the horizon . I also want to know what is going on if this is the environment I go all in on for the rest of my natural computing life - for some time, I have thought emacs is the only argument for this endeavour. My goal is not to “go minimal” as is the pervasive meme in the emacs/unix world - but to reach feature parity with what I was previously doing in doom, and to do it in a way that is potentially lighter, all while understanding and becoming a builder not just some passive consumer. Studium is organized as a set of modular files within our directory, each responsible for a coherent (and, as much as possible, singular) domain. The loads them in order at the end of the file, permitting ease of modularity. No magic; everything is right there. While I don’t think emacs load time is the end-all-be-all , I would like to aim for as quick a start-up time as possible. This is currently sub 1 second on all my machines (including my phone). Doom makes early init fairly opaque to the user, so it’s something that I really went deep on upon first seeing it in most vanilla configurations. I make sure the package system is disabled first, handing this off to elpaca (with use-package enabled), make sure garbage collection is properly setup, disable the UI that I have no use for (menu bar, scroll, etc.), and setup fonts. We do all the basic setup of user/authinfo, as well as elpaca bootstrap and defaults. We call all the lisp packages and create a modular methodology for import. I have systems that I only use org mode on (my typewriter x201 thinkpad for example) and I comment modules I don’t need out. Upon opening the repo, you will see in the directory these modules: Sets default browser for opening links and integration with universal-launcher . I have been using EWW as my default browser for a few months and enjoying it immensely. I then push to ungoogled-chromium in the event I need a heavier browser. Vertico/Marginalia/Orderless/Consult as well as Embark for actions. Corfu/Cape for completion in buffer. Just a basic splash screen on emacs launch. Simple development settings including hideshow/hl-todo/envrc for direnv integration and agenix for nix secrets Dired using Dirvish as a modern replacement for aesthetics and functionality. Editing configuration with code folding, paren matching, and all the goodies. Grammars are contained in grammars.el Elfeed configuration using elfeed-protocol to hook into the fever protocol for using miniflux as my feed reader. Elpher for gemini/gopher browsing Music player settings. You will require MPD/MPC running on your machine to get all out of this. Supports album artwork/notifcations when song switches with notify-send. IRC in emacs. What more need be said? Emacs everywhere using thanos’ implementation for wayland. I have replaced this with meow Flash is a quick jump method for anywhere on screen. I have “f” bound in normal mode to jump anywhere, immediately initiating the search and providing a jump list. If only one candidate is present, automatically jump. GNUs for usenet usage. Treesit/eglot configuration for LSP support and editing in the various languages I work in/am exploring. Adding guix support inside emacs, as I transition over to the endgame of distributions. XMPP inside emacs. Ledger for accounting in emacs. LLMs inside emacs with gptel. No more web UIs. Minor magit tweaks. Using stock keybinds mostly. Email in emacs, using Mu4e. Markdown minor adjustment. We use org-mode mostly. This is where most keybinds live and configuration for meow for modal editing. Doom modeline as a nice status bar. Move text with move-text package. Extensive org-mode configuration with keys, templates for capture, etc. roam configuration. Debating using Denote. Password-store integration in emacs. I hit Alt-p globally for a password manager. Persistence of buffers when emacs is closed/reopened. PDF, nov.el additions and configuration. ispell/flyspell integrations. Tabs with centaur tabs and nerd-icons test mode for programs. Miscellaneous additions that didn’t merit files themselves. WIP - setting up tramp to play nicely for remote editing sessions. Vterm configuration as a popup buffer and defaults. Workspaces with bufferlo as a replacement for persp. Focused writing mode using olivetti, dictionary/thesaurus integration. I have various custom lisp modules which I pulled over from DOOM, this is consistently expanding and evolving. I have brought in compline and lauds as my two main themes, running doom-themes as the engine for displaying them. I may eventually port them to vanilla configs , but I haven’t as of yet had the time. If anyone is running a vanilla version of compline/lauds, feel free to pull request the repository! I have various snippets that I have built out over the years that I copied over from DOOM, yasnippet runs them, and I continually add them as I find useful ones. I am continually asked what the best resources for learning about emacs are. This is a non-exhaustive list: This is my own personal configuration for emacs, and as such is continually evolving as my understanding grows. Check back periodically for updates. I am open for pull requests or critiques if there are better ways to do things, I am in a state of perpetual learning with emacs, which is why I love it so. As always, God bless, and until next time. If you enjoyed this post, consider Supporting my work , Checking out my book , Working with me , or sending me an Email to tell me what you think.. https://www.masteringemacs.org/reading-guide https://www.masteringemacs.org/article/beginners-guide-to-emacs https://systemcrafters.net/ https://www.youtube.com/@SystemCrafters https://protesilaos.com/ https://www.youtube.com/@protesilaos https://irreal.org https://sachachua.com/blog/ https://reddit.com/r/emacs

0 views
Maurycy Yesterday

Glassblowing #2: Making a tungsten lamp and (bad) vacuum diode

Now that I have a way to run electrodes through glass , it's time to do something with that. An old school lightbulb is rather simple: just a thin wire that gets hot enough to glow. However, to produce anything approaching white light, the wire must get to around 2500 C. While conductors like tungsten or graphite can survive those temperatures, they all burn on contact with air. To prevent this, I'll be sealing my lamp in glass under vacuum: no air, no problem. Some ceramics start conducting once heated, and being oxides, are completely unaffected by oxygen. Open air "Nernst lamps" did enjoy brief popularity in the 1890-1900s, but because of the added complexity of preheating the filament, they were replaced by filament lamps once vacuum pumps became good enough for commercial production. To start, I bent some some 0.3mm diameter tungsten wire into a "U" shape, and twisted a length of very fine 0.012 mm tungsten wire onto the free ends. I cut one side of the lead frame shorter so that the filament would sit diagonally: allowing it to be reasonably long without looping it around which could result in a short. To make the bulb, I partially inserted the lead frame into a glass tube, heated the end with an oxy-propane torch and pinched the glass onto the wires: Once one end was sealed, I connected the other to a rotary vane vacuum pump, and pumped it down while lightly heating the tube to remove moisture. After a few minutes, I headed the middle of the tube to sale the bulb, and pulled off the excess tubing. After the glass cooled, I cut the middle of the wire "U" to separate the leads: Glowing at 4 volts The finished lamp glows nicely between 200 and 400 mA (3-6 V and 0.5-2.5 W): I didn't stretch the filament tight enough and it ended up touching the glass, which creates a dim spot. The glass is borosilicate, so I'm not too worried about cracking, but it's still not ideal. I've tested the bulb up to 10 volts (~7 W), which is bright to light up a whole room, and the creates white light instead of the orange-ish color seen at low power — but it also gets very hot and won't last very long. In addition to color, the filament's temperature also affects the bulb's efficiency: a low temperature filament emits the vast majority of it's light in the infrared. A hot filament emits more visible light per watt, but tungsten evaporates faster leading to early failure. This tradeoff between lifespan and color/efficiency is why most light bulbs have rather short lifespans... or at least they did until we stopped using filaments. As an experiment , I ran a length of wire through a hole in the glass tube before evacuating it: The idea was to observe thermionic emission: when the filament is white hot, the atom's have enough kinetic energy to knock electrons into the vacuum. If the cold electrode is at a positive voltage, these electrons allow a small current to flow. If it's negative, the free electrons are repelled and nothing happens. While a diode isn't terribly exciting, it's the basis of more interesting devices like triodes, X-ray tubes and CRTs. ... and it's terrible : only conducting 1 uA with 700 V of bias between the filament and anode. Reverse biased, it conducts around 50 nA, mostly from the photoelectric effect. I suspect this is the result of two problems. Tungsten wire contains trapped gasses, which are released when it's heated. To avoid ruining the vacuum, the filament should be run while pumping down the tube, which I forgot to do. Second, the anode area is really small: Its ~6 mm of 0.3 mm wire, several centimeters away from the filament. Most emitted electrons will miss the anode and create a negative charge on the glass, which impedes current flow. Real vacuum diodes surrounding the filament in a metal tube, but I didn't do that because I wanted it to work as a light bulb. Just for fun , here's a photograph of my spool of filament wire, lit by the bulb made using it: https://en.wikipedia.org/wiki/Nernst_lamp : those lamps. https://www.youtube.com/watch?v=-spTvp5-sf0 : Using one. /projects/glass/1/ : Considerations for sealing metal through glass http://www.rhunt.f9.co.uk/Glass_Blowing/Filament_Lamp_A/Filament_Lamp_A_Page1.htm : another homemade incandescent lamp

0 views

Nix for Haskell: Static Builds

In the previous post , we learned how to get started with managing and building a Haskell project with Nix . In this post, we learn how to easily create statically-linked executables for Haskell projects with Nix. This post was originally published on abhinavsarkar.net . This post is a part of the series: Nix for Haskell . I recommend going through the previous post , because we are going to start off from where we left last time (ignoring the bonus sections). This is how our project’s directory tree looks at this point: is the default generated main file that prints “Hello, Haskell!”. is the default generated Cabal file. are generated by Niv to pin Nixpkgs to a particular revision. provides the nixpkgs that we use for building tools and dependencies. and build the package and manage the Nix shell respectively. We are not going to touch any of these files in this post. Let’s get started. A static build is an executable that is statically-linked against all the libraries it depends on. This is in contrast to a dynamically-linked executable, which contains references to the libraries it depends on, and those libraries are loaded and linked when the executable runs. While dynamic linking has its benefits , the main advantage of static linking is that the executable can be shipped by itself, without needing to ship or install dependency libraries. This makes it quite attractive for deploying backend services. You download and deploy that one binary executable file and you are done! No need to care about installing and maintaining its dependencies. Many compilers support static builds— Go and Rust being two. Haskell compiler GHC also supports it, but not out-of-the-box. To statically link a Haskell executable, we need to configure GHC itself, and then configure the executable build as well. We also need to configure GHC to link with musl libc. That’s where Nix helps us by smoothing out the process 1 . As mentioned, first we need a GHC configured to do static builds. We create a nixpkgs derivation, separate from , that contains the custom configured GHC. Let’s go over it piece-by-piece. First, we take the and parameters, letting us build the package for different architectures ( X86-64 and AArch64 ), and for different GHC versions. We default the to the default GHC in nixpkgs. The derivation is same as , except we add some overlays. The first overlay adds the custom configured GHC for static builds. We enable certain configurations for that purpose: The related lines set the custom GHC as the compiler for Haskell-based tools used in Nix 2 . The second overlay makes —the tool used to convert files into Nix derivations—use the custom GHC. The third overlay disables documentation generation, testing, and profiling of all Haskell libraries built with the custom GHC. We do this to save the build time, assuming that static builds are for release only, and the docs, tests, and profiling are done using a normal GHC. Building this custom GHC may take anywhere from several minutes to several hours depending on the build machine configuration 3 4 . But this is a one-time price to pay, as long as we keep the GHC build around. Next, we configure our package to be built as a statically-linked executable. The file is equivalent of the file from the previous post, but builds statically-linked exes. Let’s go over the file in parts. also takes and as parameters, and passes them to to create the nixpkgs with the custom GHC as described above. This give us , from which we get the version. is same nixpkgs, except every executable in it links to musl libc. We capture this as , and use it to build our Haskell package. When linking the executable, we need to link it against static version of all the dependency libraries it depends on. That’s what file provides us. We’ll look at it in the next section, but for now, we see that it gives us the , , and libraries 5 . Finally, we get to the package configuration. It starts the same as , using to connect the Haskell project to Nix, but then, we provide a list of custom configurations. We disable Haddock docs, hyperlinked source docs, coverage tests, profiling, and shared library build. We enable static executable build and dead code elimination. Then we configure cabal to run builds with multithreading, and add to its list of build tools. Then, we add many configuration flags: Finally, the last function in the pipeline uses UPX to compress the output executable. This generally results in a large reduction in the binary size 7 . Now we can actually build the statically-linked exe: The first and second line above build the exe for the X86-64 and AArch64 architectures with the default GHC version. The third line specifies a different GHC version to build with. Here is the cleaned-up output log for the first command: The output log mentions: patchelf: cannot find section ‘.dynamic’. The input file is most likely statically linked We can also verify for ourselves: There is one last thing to take care of. Dynamically-linked Haskell builds contain references to their dependency libraries and GHC that was used to build it. If you use or install a dynamically-linked executable, it creates Nix GC roots for the libraries and GHC, preventing them from being garbage-collected by Nix. But statically-linked builds have no references to anything, as intended. So we need to create GC roots by ourselves to the libraries and the GHC toolchain. This is even more important because building the custom GHC may be an extremely time-consuming affair. First, we list all dependencies in a separate file: This file lists the dependency libraries and the GHC toolchain. Notice how we override each library’s config to make it statically-linkable. I’ve included some additional libraries here ( and ) that are generally used by Haskell projects, but we don’t use them in this project. You may have to add more of such libraries depending on your project’s dependencies. We already saw how we use this file in . Now, we use it to create Nix GC roots: simply gathers all dependencies from and creates a directory with symlinks to them. This brings us to the finale. We create a bash script that builds the statically-linked executable, and creates Nix GC roots for all dependencies and the toolchain: The root is created at for X86-64 architecture, for example. You can use to explore it. This concludes our short tutorial on how to build statically-linked executables for Haskell projects with Nix. One more thing static builds are great for: wrapping them into Docker images. Since they are much smaller than dynamically-linked executables and their dependencies combined, they are better to package as Docker images. Here’s how we do it: This image also shows how to package extra Nix packages in images, setting up a non-root user to run the executable, and setting up user-owned directories to expose as volumes. We can build the image by running: Then we can load and run the image on Docker like so: This post shows how to configure GHC and Haskell projects to build statically-linked executables that are fully portable and independent. If your Haskell project has any complex requirements, such as custom dependency versions, patched dependencies, custom non-Haskell dependencies etc., this setup may not scale. In such case you can either grow this setup by learning Nix in more depth with the help of the official Haskell with Nix docs and this great tutorial , or switch to using a framework like haskell.nix or haskell-flake . For dealing with complex static builds, static-haskell-nix project may be of help. If you have any questions or comments, please leave a comment below. If you liked this post, please share it. Thanks for reading! I have tested this setup for GHC 9.10+ and X86-64 and AArch64 architectures only. ↩︎ Without this config, Nix will build a separate GHC for building Haskell-based tools used in Nix. ↩︎ You may need a remote Nix Linux builder to build GHC and your package if you are not on Linux or not on the right architecture. You may set up a remote builder or Linux builder on macOS . ↩︎ Building GHC is memory intensive. You may require few GBs of RAM. ↩︎ Some of your project’s dependency libraries may link to GMP directly. In such cases, the libraries provide Cabal flags to remove GMP dependency. If you don’t want GMP linked to your executable, you’ll need to override the Nix derivation for such libraries to pass those Cabal flags. ↩︎ I learned about using these flags from the post “Linking Smaller Haskell Binaries” . It mentions few mores tricks that may be useful to you. ↩︎ Note that we get the tools and from , the original nixpkgs, not the musl one. We don’t need musl version of these tools for them to work, and doing that would simply cause our builds to take longer. ↩︎ This post is a part of the series: Nix for Haskell . Thanks for reading this post via feed. Feeds are great, and you're great for using them. ♥ This post was originally published on abhinavsarkar.net . Read more of my posts and notes . Getting Started Static Builds 👈 Static Builds Enabling Static Builds in GHC Configuring the Application Rooting Static Build Dependencies Bonus: Building a Docker Image I have tested this setup for GHC 9.10+ and X86-64 and AArch64 architectures only. ↩︎ Without this config, Nix will build a separate GHC for building Haskell-based tools used in Nix. ↩︎ You may need a remote Nix Linux builder to build GHC and your package if you are not on Linux or not on the right architecture. You may set up a remote builder or Linux builder on macOS . ↩︎ Building GHC is memory intensive. You may require few GBs of RAM. ↩︎ Some of your project’s dependency libraries may link to GMP directly. In such cases, the libraries provide Cabal flags to remove GMP dependency. If you don’t want GMP linked to your executable, you’ll need to override the Nix derivation for such libraries to pass those Cabal flags. ↩︎ I learned about using these flags from the post “Linking Smaller Haskell Binaries” . It mentions few mores tricks that may be useful to you. ↩︎ Note that we get the tools and from , the original nixpkgs, not the musl one. We don’t need musl version of these tools for them to work, and doing that would simply cause our builds to take longer. ↩︎ Getting Started Static Builds 👈

0 views
Blargh Yesterday

I fixed shell pipes

In a previous post I made pipes in unix shells more reliable. Well, it had some drawbacks. I’ll summarize the problem, the failed previous version, and then show the new and improved one. Downstream processes in a unix shell pipe cannot know if the upstream finished successfully, or exited with an error. This means that it can’t know if it should “commit” the data it received. Example uses: In both of these cases you want the right hand side to STOP, and not finalize the upload or commit the transaction. This works fine for simple cases, but doesn’t support or per-command environment variables very well. And I don’t want to invent a complex language, so my replacement took a different path. wp on github . instead wraps the input and/or output with a very minimal encapsulating protocol. This allows normal data to pass through, but still allows the downstream to get as metadata. If the data stream ends before receiving the marker, then do not commit . The wrapped downstream child process sees this as remaining open, and instead it’s getting terminated with a signal. can either encapsulate when it wraps something that o utputs data, with , or decapsulate and receive the EOF marker when it’s handling i nput data, or both.

0 views
Xe Iaso Yesterday

I hate compilers

Anubis is about to get WebAssembly-based proof of work checks so that administrators can use a non-SHA256 proof of work method to protect their websites. Part of the implementation goals of this work is that the check logic is defined in one place on both client and server. The client and server will then hook into the WebAssembly in order to make sure they're running in lockstep. However, one small problem comes up. What do you do when the client has WebAssembly disabled? I really don't want to de-facto lock people out of websites. Anubis exists in an impossible balance of user experience, administrator experience, and developer experience and any change to any of these factors disrupts the balance for other factors. To work around this and also fulfill the goal of having check logic defined once , I decided to take inspiration from the legendary talk The Birth and Death of JavaScript and just recompile the WebAssembly to JavaScript. Sure, the resulting JavaScript will be slower than the equivalent WebAssembly (even more so because disabling WASM usually disables the JavaScript JIT, the thing that makes JavaScript fast), but it will finish eventually . Hopefully it will be more efficient than the existing JavaScript is on lower end hardware, but research is required. Luckily enough, the tool I need ( from the binaryen project ) is packaged in Linux distributions. The bad news is that distributions ship ancient versions of it that don't get the same output as the version on my development machine's copy from Homebrew . In order to really make sure that the output of this is deterministic (essential for reproducible builds), I need to bundle a copy of . So I did that by building a version of compiled to WebAssembly with wasi-sdk . The rest of the article is the tale of reproducibility woe that lead to the implementation I ended up with. Buckle up and enjoy the ride! Back up a sec, this doesn't make sense to me. If you have the same bytes of input to a compiler, you should get the same bytes of output assuming that the compiler flags, target, and other platform details are controlled for right? A compiler is just a deterministic function of input source code becomes output bytecode, right? lol you'd think, but no, it's not. In theory it is (and for small scale compilers it definitely is), but in practice compilers are strange and complicated beasts containing multitudes that no mere mortal can fully comprehend on their own. There are a shocking number of ways to accidentally create nondeterministic output when doing C/C++ development. One of the easiest is to use the builtin and macros to stamp a build with the time the compiler was executed at: Building and running it once gets me this: Another time it gets me this: Even though the source code had the same bytes , the output of the compiler was wildly different. In order for users and packagers to trust the binaries of I'm committing to the Anubis repo, I need to make sure that you can build the same version I built, down to the same bytes . For an added bonus, you should be able to build this on your machine and get the same bytes I got. That sure does sound like a great ideal, it would be horrible if something unforeseen came up to ruin it! Among other tools like , binaryen has a bunch of other useful tools such as . optimizes WebAssembly compiler output to let you eke out more performance. This doesn't work in every circumstance, but when it does work it makes a huge difference. As such, clang shells out to when doing builds. This normally makes sense, but in this case it caused builds to fail on my DGX Spark because its version of is too old: Compared to my workstation which installs from Homebrew : Turns out that wasi-sdk and binaryen rely on the WebAssembly Exceptions extension . This is a reasonable thing to assume given that wasi-sdk mostly assumes you're building things for web browsers and 93.86% of browser users have a browser engine new enough to support it. C++ is also one of the main places where exceptions are used, so I guess WebAssembly-native exception handling removes a lot of boilerplate here. Both wasmtime and wazero require you to flag into exception support. This is fine; we can just pass to wasmtime and use a custom runner harness for wazero. The annoying part is what happens when my arm machine's anemic build of wasm-opt sees exception handling instructions, causing it to exit. This made the build fail. The solution was to pass at the linking step. This removed one angle of irreproducibility. I guess in the future we could make it use the version of it just built to optimize the output, but that may be a premature optimization for now. The version of clang that I use to compile has some address-sensitive code generation hiding in its exception handling path. Raw pointer values leak into the order a handful of blocks come out in. This surfaces as every build differing from the next by about 29 bytes: To make this easier to spot, here's a partial disassembly: The computation is nearly identical, but the byte order is just different enough to also make the catch references differ. This also fires when you build this pinned version of wasm2js on arm64 machines because its pointer iteration order is different from it is on my workstation. To work around this, I took two steps: I also made a CI job ensure this: To be extra sure, we have this job run on both x86_64 and arm64 hosts. I'd really love to have this be reproducible across hosts, but that's an upstream LLVM bug that I am not powerful enough to tackle. If you work on LLVM and are reading this, it would be nice to set a seed of some kind to ensure that this iteration order is fixed across architectures. At the very least builds are deterministic within architectures. This may have to be good enough for now. Disable address-space randomization for this build using . Create known good sha256 checksums for both x86_64 and arm64 via building this program on machines I trust.

0 views