CINXE.COM
Planet Debian
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>Planet Debian</title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="generator" content="http://intertwingly.net/code/venus/" /> <link rel="stylesheet" href="common/planet.css" type="text/css" /> <link rel="icon" type="image/x-icon" href="common/favicon.ico" /> <link href="rss10.xml" rel="alternate" type="application/rss+xml" title="RSS 1.0 Feed" /> <link href="rss20.xml" rel="alternate" type="application/rss+xml" title="RSS 2.0 Feed" /> <link href="atom.xml" rel="alternate" type="application/atom+xml" title="Atom Feed" /> <script type="text/javascript" src="common/hide.js"></script> <script type="text/javascript"> <!-- window.onload=hideHosts; --> </script> </head> <body> <div id="header"> <div id="upperheader"> <div id="logo"> <a href="https://www.debian.org/" title="Debian Home"><img src="common/Pics/openlogo-50.png" alt="Debian" width="50" height="61" /></a> </div><!-- end logo --> <p class="section"><a href="/">planet</a></p> </div><!-- end upperheader --> <div id="navbar"> <p class="hidecss"><a href="#inner">Skip Quicknav</a></p> <ul> <li><a href="https://www.debian.org/intro/about">About Debian</a></li> <li><a href="https://www.debian.org/distrib/">Getting Debian</a></li> <li><a href="https://www.debian.org/support">Support</a></li> <li><a href="https://www.debian.org/devel/">Developers' Corner</a></li> </ul> </div><!-- end navbar --> <p id="breadcrumbs"><a href="https://planet.debian.org/">Planet Debian</a></p> </div><!-- end header --> <div id="content"> <h1>March 22, 2025</h1> <div class="channel"> <a href="http://dirk.eddelbuettel.com/blog"> <img class="face" src="heads/dirk.png" width="65" height="90" alt="hackergotchi for Dirk Eddelbuettel" /> </a> <h2 class="planet-title"> <a href="http://dirk.eddelbuettel.com/blog" title="Thinking inside the box">Dirk Eddelbuettel</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7_hide\" onClick=\"exclude( 'http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7_show\" style=\"display:none;\" onClick=\"show( 'http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7" class="http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7"> <div class="entry"> <h3 class="entry-title"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7">RcppZiggurat 0.1.7 on CRAN: New Generators, Many Updates</a> </h3> <div class="content"> <p><img alt="ziggurats" src="http://dirk.eddelbuettel.com/code/images/zigspeed.png" style="float: left; margin: 0 40px 10px 0;" width="480" /></p> <p>A new release 0.1.7 of <a href="https://dirk.eddelbuettel.com/code/rcpp.ziggurat.html">RcppZiggurat</a> is now on the <a href="https://cran.r-project.org">CRAN</a> network for <a href="https://www.r-project.org">R</a>. This marks the first release in four and a half years.</p> <p>The <a href="https://dirk.eddelbuettel.com/code/rcpp.ziggurat.html">RcppZiggurat</a> package updates the code for the <a href="https://en.wikipedia.org/wiki/Ziggurat_algorithm">Ziggurat generator</a> by <a href="https://en.wikipedia.org/wiki/George_Marsaglia">Marsaglia</a> and others which provides very fast draws from a Normal distribution. The package provides a simple C++ wrapper class for the generator improving on the very basic macros, and permits comparison among several existing Ziggurat implementations. This can be seen in the figure where Ziggurat from this package dominates accessing the implementations from the <a href="https://www.gnu.org/software/gsl/">GSL</a>, <a href="https://quantlib.org/index.shtml">QuantLib</a> and <a href="https://gretl.sourceforge.net/">Gretl</a>—all of which are still way faster than the default Normal generator in R (which is of course of higher code complexity).</p> <p>This release brings a number of changes. Notably, based on the work we did with the new package <a href="https://dirk.eddelbuettel.com/code/zigg.html">zigg</a> (more on that in a second), we now also expose the Exponential generator, and the underlying Uniform generator. Otherwise many aspects of the package have been refreshed: updated builds, updated links, updated CI processes, more use of DOIs and more. The other big news is <a href="https://dirk.eddelbuettel.com/code/zigg.html">zigg</a> which should now be the preference for <em>deployment</em> of <a href="https://en.wikipedia.org/wiki/Ziggurat_algorithm">Ziggurat</a> due to its much lighter-weight and zero-dependency setup.</p> <p>The <code>NEWS</code> file entry below lists all changes.</p> <blockquote> <h4 id="changes-in-version-0.1.7-2025-03-22">Changes in version 0.1.7 (2025-03-22)</h4> <ul> <li><p>The CI setup was updated to use <code>run.sh</code> from <a href="https://eddelbuettel.github.io/r-ci/">r-ci</a> (Dirk).</p></li> <li><p>The windows build was updated to GSL 2.7, and UCRT support was added (Jeroen in <a href="https://github.com/eddelbuettel/rcppziggurat/pull/16">#16</a>).</p></li> <li><p>Manual pages now use JSS DOIs for references per CRAN request</p></li> <li><p>README.md links and badges have been updated</p></li> <li><p>Continuous integration actions have been updated several times</p></li> <li><p>The DESCRIPTION file now uses Authors@R as mandated</p></li> <li><p>Use of multiple cores is eased via a new helper function reflecting option <code>mc.core</code> or architecture defaults, used in tests</p></li> <li><p>An inline function has been added to avoid a compiler nag</p></li> <li><p>Support for exponential RNG draws <code>zrexp</code> has been added, the internal uniform generator is now also exposed via <code>zruni</code></p></li> <li><p>The vignette bibliography has been updated, and switched to DOIs</p></li> <li><p>New package <span class="pkg">zigg</span> is now mentioned in DESCRIPTION and vignette</p></li> </ul> </blockquote> <p>Courtesy of my <a href="https://dirk.eddelbuettel.com/cranberries/">CRANberries</a>, there is a <a href="https://dirk.eddelbuettel.com/cranberries/2025/03/22#RcppZiggurat_0.1.7">diffstat report</a> relative to previous release. More detailed information is on the <a href="https://dirk.eddelbuettel.com/code/rcpp.ziggurat.html">Rcppziggurat page</a> or the <a href="https://github.com/eddelbuettel/rcppziggurat">GitHub repository</a>.</p> <p style="font-size: 80%; font-style: italic;"> This post by <a href="https://dirk.eddelbuettel.com">Dirk Eddelbuettel</a> originated on his <a href="https://dirk.eddelbuettel.com/blog/">Thinking inside the box</a> blog. If you like this or other open-source work I do, you can <a href="https://github.com/sponsors/eddelbuettel">sponsor me at GitHub</a>. </p><p></p> </div> <p class="date"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/22#rcppziggurat_0.1.7">22 March, 2025 05:25PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="https://blog.luke.wf/search/label/debian-planet"> <img class="face" src="heads/lfaraone-mini.png" width="65" height="85" alt="hackergotchi for Luke Faraone" /> </a> <h2 class="planet-title"> <a href="https://blog.luke.wf/search/label/debian-planet" title="Luke W. Faraone">Luke Faraone</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html_hide\" onClick=\"exclude( 'https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html_show\" style=\"display:none;\" onClick=\"show( 'https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html" class="https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html">I'm running for the OSI board... maybe</a> </h3> <div class="content"> <p>The Open Source Initiative has two classes of board seats: Affiliate seats, and Individual Member seats. </p><p>In the upcoming election, each affiliate can nominate a candidate, and each affiliate can cast a vote for the Affiliate candidates, but there's only 1 Affiliate seat available. I initially expressed interest in being nominated as an Affiliate candidate via Debian. But since <a href="https://ebb.org/bkuhn/">Bradley Kuhn</a> is also running for an Affiliate seat with a similar platform to me, especially with regards to the OSAID, I decided to run as part of an aligned "ticket" as an Individual Member to avoid contention for the 1 Affiliate seat.</p><p>Bradley and I discussed running on a similar ticket around 8/9pm Pacific, and I submitted my candidacy around 9pm PT on 17 February. </p><p>I was dismayed when I received the following mail from <span style="white-space: normal;">Nick Vidal:</span></p><p></p><blockquote><span face="Arial, Helvetica, sans-serif" style="background-color: white; color: #222222; font-size: small;">Dear Luke,</span><br style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span face="Arial, Helvetica, sans-serif" style="background-color: white; color: #222222; font-size: small;">Thank you for your interest in the OSI Board of Directors election. Unfortunately, we are unable to accept your application as it was submitted after the official deadline of Monday Feb 17 at 11:59 pm UTC. To ensure a fair process,<b> we must adhere to the deadline for all candidates.</b></span><br style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span face="Arial, Helvetica, sans-serif" style="background-color: white; color: #222222; font-size: small;">We appreciate your enthusiasm and encourage you to stay engaged with OSI’s mission. We hope you’ll consider applying in the future or contributing in other meaningful ways.</span><br style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span face="Arial, Helvetica, sans-serif" style="background-color: white; color: #222222; font-size: small;">Best regards,</span><br style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span face="Arial, Helvetica, sans-serif" style="background-color: white; color: #222222; font-size: small;">OSI Election Teams</span></blockquote><p>Nowhere on the <a href="https://opensource.org/blog/osis-board-of-directors-in-2025-details-about-the-elections">"OSI’s board of directors in 2025: details about the elections"</a> page do they list a timezone for closure of nominations; they simply list Monday 17 February. </p><p>The OSI's contact address is in California, so it seems arbitrary and capricious to retroactively define all of these processes as being governed by UTC.</p><p>I was not able to participate in the "potential board director" info sessions accordingly, but people who attended heard that the importance of accommodating differing TZ's was discussed during the info session, and that OSI representatives mentioned they try to accommodate TZ's of everyone. This seems in sharp contrast with the above policy. </p><p>I urge the OSI to reconsider this policy and allow me to stand for an Individual seat in the current cycle. </p><p><b>Upd</b>, N.B.: to people writing about this, I use they/them pronouns</p><p></p> </div> <p class="date"> <a href="https://blog.luke.wf/2025/02/im-running-for-osi-board-maybe.html">22 March, 2025 04:30PM</a> by Luke Faraone (noreply@blogger.com) </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="https://anarc.at/tag/debian-planet/" title="pages tagged debian-planet">Antoine Beaupré</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://anarc.at/blog/2025-03-21-losing-war-internet/_hide\" onClick=\"exclude( 'https://anarc.at/blog/2025-03-21-losing-war-internet/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://anarc.at/blog/2025-03-21-losing-war-internet/_show\" style=\"display:none;\" onClick=\"show( 'https://anarc.at/blog/2025-03-21-losing-war-internet/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://anarc.at/blog/2025-03-21-losing-war-internet/" class="https://anarc.at/blog/2025-03-21-losing-war-internet/"> <div class="entry"> <h3 class="entry-title"> <a href="https://anarc.at/blog/2025-03-21-losing-war-internet/">Losing the war for the free internet</a> </h3> <div class="content"> <p>Warning: this is a long ramble I wrote after an outage of my home internet. You'll get your regular scheduled programming shortly.</p> <p>I didn't realize this until relatively recently, but we're at war.</p> <p>Fascists and capitalists are trying to take over the world, and it's bringing utter chaos.</p> <p>We're more numerous than them, of course: this is only a handful of people screwing everyone else over, but they've accumulated so much wealth and media control that it's getting really, really hard to move around.</p> <p>Everything is surveilled: people are carrying tracking and recording devices in their pockets at all time, or they drive around in surveillance machines. Payments are all turning digital. There's cameras everywhere, including in cars. Personal data leaks are so common people kind of assume their personal address, email address, and other personal information <em>has</em> already been leaked.</p> <p>The internet itself is collapsing: most people are using the network only as a channel to reach a "small" set of "<a href="https://en.wikipedia.org/wiki/Hyperscale_computing">hyperscalers</a>": mind-boggingly large datacenters that don't really operate like the old internet. Once you reach the local endpoint, you're not on the internet anymore. Netflix, Google, Facebook (Instagram, Whatsapp, Messenger), Apple, Amazon, Microsoft (Outlook, Hotmail, etc), all those things are not really the internet anymore.</p> <p>Those companies operate over the "<a href="https://en.wikipedia.org/wiki/Internet">internet</a>" (as in the <a href="https://en.wikipedia.org/wiki/Internet_protocol_suite">TCP/IP</a> network), but they are not an "interconnected network" as much as their own, gigantic silos so much bigger than everything else that they essentially dictate how the network operates, regardless of standards. You access it over "the <a href="https://en.wikipedia.org/wiki/World_Wide_Web">web</a>" (as in "<a href="https://en.wikipedia.org/wiki/HTTP">HTTP</a>") but the fabric is not made of interconnected links that cross sites: all those sites are trying really hard to keep you captive on their platforms.</p> <p>Besides, you <em>think</em> you're writing an email to the state department, for example, but you're really writing to Microsoft Outlook. That app your university or border agency tells you to install, the backend is not hosted by those institutions, it's on Amazon. Heck, even Netflix is on Amazon.</p> <p>Meanwhile I've been operating my own mail server first under my bed (yes, really) and then in a cupboard or the basement for almost three decades now. And what for?</p> <p>So I can tell people I can? Maybe!</p> <p>I guess the reason I'm doing this is the same reason people are suddenly asking me about <a href="https://wiki.reseaulibre.ca/">the (dead) mesh</a> again. People are worried and scared that the world has been taken over, and they're right: we have gotten seriously screwed.</p> <p>It's the same reason I keep doing radio, minimally know how to grow food, ride a bike, build a shed, paddle a canoe, archive and document things, talk with people, host an assembly. Because, when push comes to shove, there's no one else who's going to do it for you, at least not the way that benefits the people.</p> <p>The Internet is one of humanity's greatest accomplishments. Obviously, oligarchs and fascists are trying to destroy it. I just didn't expect the tech bros to be flipping to that side so easily. I thought we were friends, but I guess we are, after all, enemies.</p> <p>That said, that old internet is still around. It's getting harder to host your own stuff at home, but it's not impossible. Mail is tricky because of reputation, but it's also tricky in the cloud (don't get fooled!), so it's not that much easier (or cheaper) there.</p> <p>So there's things you can do, if you're into tech.</p> <p>Share your wifi with your neighbours.</p> <p>Build a LAN. Throw a wire over to your neighbour too, it works better than wireless.</p> <p>Use <a href="https://www.torproject.org/">Tor</a>. <a href="https://community.torproject.org/relay/">Run a relay</a>, a <a href="https://snowflake.torproject.org/">snowflake</a>, a <a href="https://blog.torproject.org/call-for-webtunnel-bridges/">webtunnel</a>.</p> <p>Host a web server. Build a site with a static site generator and throw it in the wind.</p> <p>Download and share <a href="https://en.wikipedia.org/wiki/BitTorrent">torrents</a>, and why not a <a href="https://en.wikipedia.org/wiki/BitTorrent_tracker">tracker</a>.</p> <p>Run an <a href="https://en.wikipedia.org/wiki/IRC">IRC</a> server (or <a href="https://anarc.at/blog/2022-06-17-matrix-notes/">Matrix</a>, if you want to federate and lose high availability).</p> <p>At least use <a href="https://signal.org/">Signal</a>, not Whatsapp or Messenger.</p> <p>And yes, why not, run a mail server, join a mesh.</p> <p>Don't write new software, there's plenty of that around already.</p> <p>(Just kidding, you can write code, <a href="https://en.wikipedia.org/wiki/Cypherpunk">cypherpunk</a>.)</p> <p>You can do <em>many</em> of those things just by setting up a <a href="https://www.freedombox.org/">FreedomBox</a>.</p> <p>That is, after all, the internet: people doing their own thing for their own people.</p> <p>Otherwise, it's just like sitting in front of the television and watching the ads. Opium of the people, like the good old time.</p> <p>Let a billion droplets build the biggest multitude of clouds that will storm over this world and rip apart this fascist conspiracy.</p> <p>Disobey. Revolt. Build.</p> <p>We are more than them.</p> </div> <p class="date"> <a href="https://anarc.at/blog/2025-03-21-losing-war-internet/">22 March, 2025 04:25AM</a> </p> </div> </div> </div> <div class="channel"> <div id="https://anarc.at/blog/2025-03-21-another-home-outage/" class="https://anarc.at/blog/2025-03-21-another-home-outage/"> <div class="entry"> <h3 class="entry-title"> <a href="https://anarc.at/blog/2025-03-21-another-home-outage/">Minor outage at Teksavvy business</a> </h3> <div class="content"> <p>This morning, internet was down at home. The last time I had such an issue was in <a href="https://anarc.at/blog/2023-02-08-major-outage/">February 2023</a>, when my provider was Oricom. Now I'm with a business service at Teksavvy Internet (TSI), in which I pay 100$ per month for a 250/50 mbps business package, with a static IP address, on which I run, well, everything: email services, this website, etc.</p> <h1 id="mitigation">Mitigation</h1> <h2 id="email">Email</h2> <p>The main problem when the service goes down like this for prolonged outages is email. Mail is pretty resilient to failures like this but after some delay (which varies according to the other end), mail starts to drop. I am actually not sure what the various settings are among different providers, but I would assume mail is typically kept for about 24h, so that's our mark.</p> <p>Last time, I setup VMs at Linode and Digital Ocean to deal better with this. I have actually kept those VMs running as DNS servers until now, so that part is already done.</p> <p>I had fantasized about Puppetizing the mail server configuration so that I could quickly spin up mail exchangers on those machines. But now I am realizing that my Puppet server is one of the service that's down, so this would not work, at least not unless the manifests can be applied without a Puppet server (say with <code>puppet apply</code>).</p> <p>Thankfully, my colleague groente did amazing work to refactor our Postfix configuration in Puppet at Tor, and that gave me the motivation to reproduce the setup in the lab. So I have finally Puppetized part of my mail setup at home. That used to be hand-crafted experimental stuff documented in a couple of pages in this wiki, but is now being deployed by Puppet.</p> <p>It's not complete yet: spam filtering (including DKIM checks and graylisting) are not implemented yet, but that's the next step, presumably to do during the next outage. The setup <em>should</em> be deployable with <code>puppet apply</code>, however, and I have refined that mechanism a little bit, with the <code>run</code> script.</p> <p>Heck, it's not even <em>deployed</em> yet. But the hard part / grunt work is done.</p> <h2 id="other">Other</h2> <p>The outage was "short" enough (5 hours) that I didn't take time to deploy the other mitigations I had deployed in the previous incident.</p> <p>But I'm starting to seriously consider deploying a web (and caching) reverse proxy so that I endure such problems more gracefully.</p> <h1 id="side-note-on-proper-servics">Side note on proper servics</h1> <p>Typically, I tend to think of a properly functioning service as having four things:</p> <ol> <li>backups</li> <li>documentation</li> <li>monitoring</li> <li>automation</li> <li>high availability</li> </ol> <p>Yes, I miscounted. This is why you have high availability.</p> <h2 id="backups">Backups</h2> <p>Duh. If data is maliciously or accidentally destroyed, you need a copy somewhere. Preferably in a way that malicious joe can't get to.</p> <p>This is harder than you think.</p> <h2 id="documentation">Documentation</h2> <p>I have an entire <a href="https://gitlab.torproject.org/tpo/tpa/wiki-replica/-/raw/master/service/template.md?ref_type=heads">template</a> for this. Essentially, it boils down to using <a href="https://diataxis.fr/">https://diataxis.fr/</a> and <a href="https://bluesock.org/~willkg/blog/dev/auditing_projects.html">this "audit" guide</a>. For me, the most important parts are:</p> <ul> <li>disaster recovery (includes backups, probably)</li> <li>playbook</li> <li>install/upgrade procedures (see automation)</li> </ul> <p>You probably know this is hard, and this is why you're not doing it. Do it anyways, you'll think it sucks, but you'll be really grateful for whatever scraps you wrote when you're in trouble.</p> <h2 id="monitoring">Monitoring</h2> <p>If you don't have monitoring, you'll know it fails too late, and you won't know it recovers. Consider high availability, work hard to reduce noise, and don't have machine wake people up, that's literally torture and is against the Geneva convention.</p> <p>Consider predictive algorithm to prevent failures, like "add storage within 2 weeks before this disk fills up".</p> <p>This is harder than you think.</p> <h2 id="automation">Automation</h2> <p>Make it easy to redeploy the service elsewhere.</p> <p>Yes, I know you have backups. That is not enough: that typically restores data and while it can also include configuration, you're going to need to change things when you restore, which is what automation (or call it "configuration management" if you will) will do for you anyways.</p> <p>This also means you can do unit tests on your configuration, otherwise you're building legacy.</p> <p>This is probably as hard as you think.</p> <h2 id="high-availability">High availability</h2> <p>Make it not fail when one part goes down.</p> <p>Eliminate single points of failures.</p> <p>This is easier than you think, except for storage and DNS (which, I guess, means it's harder than you think too).</p> <h2 id="assessment">Assessment</h2> <p>In the above 5 items, I check two:</p> <ol> <li>backups</li> <li>documentation</li> </ol> <p>And barely: I'm not happy about the offsite backups, and my documentation is much better at work than at home (and even there, I have a 15 year backlog to catchup on).</p> <p>I barely have monitoring: Prometheus is scraping parts of the infra, but I don't have any sort of alerting -- by which I don't mean "electrocute myself when something goes wrong", I mean "there's a set of thresholds and conditions that define an outage and I can look at it".</p> <p>Automation is wildly incomplete. My home server is a random collection of old experiments and technologies, ranging from Apache with Perl and CGI scripts to Docker containers running Golang applications. Most of it is not Puppetized (but the ratio is growing). Puppet itself introduces a huge attack vector with kind of catastrophic lateral movement if the Puppet server gets compromised.</p> <p>And, fundamentally, I am not sure I can provide high availability in the lab. I'm just this one guy running my home network, and I'm growing older. I'm thinking more about winding things down than building things now, and that's just really sad, because I feel <a href="https://anarc.at/blog/2025-03-21-losing-war-internet/">we're losing</a> (well that escalated quickly).</p> <h1 id="resolution">Resolution</h1> <p>In the end, I didn't need any mitigation and the problem fixed itself. I did do quite a bit of cleanup so that feels somewhat good, although I despaired quite a bit at the amount of technical debt I've accumulated in the lab.</p> <h1 id="timeline">Timeline</h1> <p>Times are in UTC-4.</p> <ul> <li>6:52: IRC bouncer goes offline</li> <li>9:20: called TSI support, waited on the line 15 minutes then was told I'd get a call back</li> <li>9:54: outage apparently detected by TSI</li> <li>11:00: no response, tried calling back support again</li> <li>11:10: confirmed bonding router outage, no official ETA but "today", source of the 9:54 timestamp above</li> <li>12:08: TPA monitoring notices service restored</li> <li>12:34: call back from TSI; service restored, problem was with the "bonder" configuration on their end, which was "fighting between Montréal and Toronto"</li> </ul> </div> <p class="date"> <a href="https://anarc.at/blog/2025-03-21-another-home-outage/">22 March, 2025 04:25AM</a> </p> </div> </div> </div> <h1>March 21, 2025</h1> <div class="channel"> <h2 class="planet-title"> <a href="https://current.workingdirectory.net/tags/debian/" title="debian on Website of Jamie McClelland">Jamie McClelland</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://current.workingdirectory.net/posts/2025/ai-changes/_hide\" onClick=\"exclude( 'https://current.workingdirectory.net/posts/2025/ai-changes/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://current.workingdirectory.net/posts/2025/ai-changes/_show\" style=\"display:none;\" onClick=\"show( 'https://current.workingdirectory.net/posts/2025/ai-changes/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://current.workingdirectory.net/posts/2025/ai-changes/" class="https://current.workingdirectory.net/posts/2025/ai-changes/"> <div class="entry"> <h3 class="entry-title"> <a href="https://current.workingdirectory.net/posts/2025/ai-changes/">AI's Actual Impact</a> </h3> <div class="content"> <p>Two years after OpenAI launched ChatGPT 3.5, humanity is not on the cusp of extinction and Elon Musk seems more responsible for job loss than any AI agent.</p> <p>However, ask any web administrator and you will learn that <a href="https://thelibre.news/foss-infrastructure-is-under-attack-by-ai-companies/">large language models are having a significant impact on the world wide web</a> (or, for a less technical account, see <a href="https://www.forbes.com/sites/emmawoollacott/2024/04/16/yes-the-bots-really-are-taking-over-the-internet/">Forbes articles on bots</a>). At <a href="https://mayfirst.coop/">May First</a>, a membership organization that has been supporting thousands of web site for over 20 years, we have never seen anything like this before.</p> <h2 id="wow-my-site-is-getting-really-popular">Wow, my site is getting really popular</h2> <p>It started in 2023. Web sites that performed quite well with a steady viewership started having traffic spikes. These were relatively easy to diagnose, since most of the spikes came from visitors that properly identified themselves as bots, allowing us to see that the big players - OpenAI, Bing, Google, Facebook - were increasing their efforts to scrape as much content from web sites as possible.</p> <p>Small brochure sites were mostly unaffected because they could be scraped in a matter of minutes. But large sites with an archive of high quality human written content were getting hammered. Any web site with a search feature or a calendar or any interface that generated exponential hits that could be followed were particularly vulnerable.</p> <p>But hey, that’s what <a href="http://www.robotstxt.org/">robots.txt</a> is for, right? To tell robots to back off if you don’t want them scraping your site?</p> <p>Eventually, the cracks began to show. Bots were ignoring robots.txt (did they ever pay that much attention to it in the first place?). Furthermore, rate limiting requests by user agent also began to fail. When you post a link on Facebook, a bot identifying itself as “facebooketernalhit” is invoked to preview the page so it can show a picture and other meta data. We don’t want to rate limit that bot, right? Except, Facebook is also using this bot to scrape your site, often bringing your site to its knees. And don’t get me started on TwitterBot.</p> <p>Eventually, it became clear that the majority of the armies of bots scraping our sites have completely given up on identifying themselves as bots and are instead using user agents indistinguishable from regular browsers. By using thousands of different IP addresses, it has become really hard to separate the real humans from the bots.</p> <h2 id="now-what">Now what?</h2> <p>So, no, unfortunately, your web site is not suddenly getting really popular. And, you are blessed with a whole new set of strategic decisions.</p> <p>Fortunately, May First has undergone a major infrastructure transition, resulting in centralized logging of all web sites and a fleet of web proxy servers that intercept all web traffic. Centralized logging means we can analyze traffic and identify bots more easily, and a web proxy fleet allows us to more easily implement rules across all web sites.</p> <p>However, even with all of our latest changes and hours upon hours of work to keep out the bots, our members are facing some hard decisions about maintaining an open web.</p> <p>One member of May First provides Google translations of their web site to every language available. But wow, that is now a disaster because instead of having every bot under the sun scrapping all 843 (a made up number) pieces of unique content on their site, the same bots are scraping 843 * (number of available languages) pieces of content on their site. Should they stop providing this translation service in order to ensure people can access their site in the site’s primary language?</p> <p>Should web sites turn off their search features that include drop down options of categories to prevent bots from systematically refreshing the search page with every possible combination of search terms?</p> <p>Do we need to alter our calendar software to avoid providing endless links into the future (ok, that is an easy one)?</p> <h2 id="whats-next">What’s next?</h2> <p>Something has to change.</p> <ul> <li> <p><strong>Lock down web 2.0.</strong> Web 2.0 brought us wonderful dynamic web sites, which Drupal and WordPress and many other pieces of amazing software have supported for over a decade. This is the software that is getting bogged down by bots. Maybe we need to figure out a way to lock down the dynamic aspects of this software to logged in users and provide static content for everyone else?</p> </li> <li> <p><strong>Paywalls and accounts everywhere.</strong> There’s always been an amazing non-financial reward to providing a web site with high quality movement oriented content for free. It populates the search engines, provides links to inspiring and useful content in moments of crises, and can galvanize movements. But these moments of triumph happen between long periods of hard labor that now seems to mostly feed capitalist AI scumbags. If we add a new set of expenses and labor to keep the sites running for this purpose, how sustainable is that? Will our treasure of free movement content have to move behind paywalls or logins? If we provide logins, will that keep the bots out or just create a small hurdle for them to automate the account creation process? What happens when we can’t search for this kind of content via search engines?</p> </li> <li> <p><strong>Cutting deals.</strong> What if our movement content providers are forced to cut deals with the AI entrepreneurs to allow the paying scumbags to fund the content creation. Eww. Enough said.</p> </li> <li> <p><strong>Bot detection.</strong> Maybe we just need to get better at bot detection? This will surely be an arms race, but would have some good benefits. Bots have also been filling out our forms and populating our databases with spam, testing credit cards against our donation pages, conducting denial of service attacks and all kinds of other irritating acts of vandalism. If we were better at stopping bots automatically it would have a lot of benefits. But what impact would it have on our web sites and the experience of using them? What about “good” bots (RSS feed readers, payment processors, web hooks, uptime detectors)? Will we cut the legs off any developer trying to automate something?</p> </li> </ul> <p>I’m not really sure where this is going, but it seems that the world wide web is about to head in a new direction.</p> </div> <p class="date"> <a href="https://current.workingdirectory.net/posts/2025/ai-changes/">21 March, 2025 12:27PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="https://diffoscope.org/" title="diffoscope">Reproducible Builds (diffoscope)</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://diffoscope.org/news/diffoscope-291-released/_hide\" onClick=\"exclude( 'https://diffoscope.org/news/diffoscope-291-released/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://diffoscope.org/news/diffoscope-291-released/_show\" style=\"display:none;\" onClick=\"show( 'https://diffoscope.org/news/diffoscope-291-released/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://diffoscope.org/news/diffoscope-291-released/" class="https://diffoscope.org/news/diffoscope-291-released/"> <div class="entry"> <h3 class="entry-title"> <a href="https://diffoscope.org/news/diffoscope-291-released/">diffoscope 291 released</a> </h3> <div class="content"> <p>The diffoscope maintainers are pleased to announce the release of diffoscope version <code class="language-plaintext highlighter-rouge">291</code>. This version includes the following changes:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ Chris Lamb ] * Make two required adjustments for the new version of the src:file package: - file(1) version 5.46 now emits "XHTML document" for .xhtml files, such as those found nested within our .epub tests. Therefore, match this string when detecting XML files. This was causing an FTBFS due to inconsistent indentation in diffoscope's output. - Require the new, upcoming, version of file(1) for a quine-related testcase after adjusting the expected output. Previous versions of file(1) had a duplicated "last modified, last modified" string for some Zip archives that has now been removed. * Add a missing subprocess import. * Bump Standards-Version to 4.7.2. </code></pre></div></div> <p>You find out more by <a href="https://diffoscope.org">visiting the project homepage</a>.</p> </div> <p class="date"> <a href="https://diffoscope.org/news/diffoscope-291-released/">21 March, 2025 12:00AM</a> </p> </div> </div> </div> <div class="channel"> <div id="https://diffoscope.org/news/diffoscope-290-released/" class="https://diffoscope.org/news/diffoscope-290-released/"> <div class="entry"> <h3 class="entry-title"> <a href="https://diffoscope.org/news/diffoscope-290-released/">diffoscope 290 released</a> </h3> <div class="content"> <p>The diffoscope maintainers are pleased to announce the release of diffoscope version <code class="language-plaintext highlighter-rouge">290</code>. This version includes the following changes:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ Chris Lamb ] * Also consider .aar files as APK files for the sake of not falling back to a binary diff. (Closes: #1099632) * Ensure all calls to out_check_output in the ELF comparator have the potential CalledProcessError exception caught. (Re: #398) * Ensure a potential CalledProcessError is caught in the OpenSSL comparator as well. * Update copyright years. [ Eli Schwartz ] * Drop deprecated and no longer functional "setup.py test" command. </code></pre></div></div> <p>You find out more by <a href="https://diffoscope.org">visiting the project homepage</a>.</p> </div> <p class="date"> <a href="https://diffoscope.org/news/diffoscope-290-released/">21 March, 2025 12:00AM</a> </p> </div> </div> </div> <h1>March 20, 2025</h1> <div class="channel"> <a href="https://wp.c9h.org/cj"> <img class="face" src="heads/cj.png" width="65" height="85" alt="hackergotchi for C.J. Collier" /> </a> <h2 class="planet-title"> <a href="https://wp.c9h.org/cj" title="debian – Clerical Rigor">C.J. Collier</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://wp.c9h.org/cj/?p=2054_hide\" onClick=\"exclude( 'https://wp.c9h.org/cj/?p=2054' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://wp.c9h.org/cj/?p=2054_show\" style=\"display:none;\" onClick=\"show( 'https://wp.c9h.org/cj/?p=2054' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://wp.c9h.org/cj/?p=2054" class="https://wp.c9h.org/cj/?p=2054"> <div class="entry"> <h3 class="entry-title"> <a href="https://wp.c9h.org/cj/?p=2054">Installing a desktop environment on the HP Omen</a> </h3> <div class="content"> <p>`dmidecode | grep -A8 ‘^System Information’`</p> <p>tells me that the Manufacturer is HP and Product Name is OMEN Transcend Gaming Laptop 14-fb0xxx</p> <p>I’m provisioning a new piece of hardware for my eng consultant and it’s proving more difficult than I expected. I must admit guilt for some of this difficulty. Instead of installing using the debian installer on my keychain, I dd’d the pv block device of the 16 inch 2023 version onto the partition set aside from it. I then rebooted into rescue mode and cleaned up the grub config, corrected the EFI boot partition’s path in /etc/fstab, ran the grub installer from the rescue menu, and rebooted.</p> <p>On the initial boot of the system, X or Wayland or whatever is supposed to be talking to this vast array of GPU hardware in this device, it’s unable to do more than create a black screen on vt1. It’s easy enough to switch to vt2 and get a shell on the installed system. So I’m doing that and investigating what’s changed in Trixie. It seems like it’s pretty significant. Did they just throw out Keith Packard’s and Behdad Esfahbod’s work on font rendering? I don’t understand what’s happening in this effort to abstract to a simpler interface. I’ll probably end up reading more about it.</p> <p>In an effort to have Debian re-configure the system for Desktop use, I have uninstalled as many packages as I could find that were in the display and human interface category, or were firmware/drivers for devices not present in this Laptop’s SoC. Some commands I used to clear these packages and re-install connamon follow:</p> <pre>``` dpkg -S /etc/X11 dpkg -S /usr/lib/firmware apt-get purge $(dpkg -l | grep -i \ -e gnome -e gtk -e x11-common -e xfonts- -e libvdpau -e dbus-user-session -e gpg-agent \ -e bluez -e colord -e cups -e fonts -e drm -e xf86 -e mesa -e nouveau -e cinnamon \ -e avahi -e gdk -e pixel -e desktop -e libreoffice -e x11 -e wayland -e xorg \ -e firmware-nvidia-graphics -e firmware-amd-graphics -e firmware-mediatek -e firmware-realtek \ | awk '{print $2}') apt-get autoremove apt-get purge $(dpkg -l | grep '^r' | awk '{print $2}') tasksel install cinnamon-desktop ```</pre> <p>And then I rebooted. When it came back up, I was greeted with a login prompt, and Trixie looks to be fully functional on this device, including the attached wifi radio, tethering to my android, and the thunderbolt-attached Marvell SFP+ enclosure.</p> <p>I’m also installing libvirt and fetched the DVD iso material for Debian, Ubuntu and Rocky in case we have a need of building VMs during the development process. These are the platforms that I target at work with gcp Dataproc, so I’m pretty good at performing maintenance operation on them at this point.</p> <div class="twitter-share"><a class="twitter-share-button" href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwp.c9h.org%2Fcj%2F%3Fp%3D2054&via=cjamescollier">Tweet</a></div> </div> <p class="date"> <a href="https://wp.c9h.org/cj/?p=2054">20 March, 2025 11:06PM</a> by C.J. Collier </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="http://sven.stormbind.net/blog/" title="a blog">Sven Hoexter</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://sven.stormbind.net/blog/posts/misc_purpose_film/_hide\" onClick=\"exclude( 'http://sven.stormbind.net/blog/posts/misc_purpose_film/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://sven.stormbind.net/blog/posts/misc_purpose_film/_show\" style=\"display:none;\" onClick=\"show( 'http://sven.stormbind.net/blog/posts/misc_purpose_film/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://sven.stormbind.net/blog/posts/misc_purpose_film/" class="http://sven.stormbind.net/blog/posts/misc_purpose_film/"> <div class="entry"> <h3 class="entry-title"> <a href="http://sven.stormbind.net/blog/posts/misc_purpose_film/">Purpose A Wellbeing Economies Film</a> </h3> <div class="content"> <p>The <a href="https://purpose.film/">film</a> is centered around the idea of establishing an alternative to the GDP as <em>the metric</em> to measure success of a country/society. The film follows mostly <a href="https://katherinetrebeck.com">Katherine Trebeck</a> on her journey of convincing countries to look beyond the GDP. I very much enjoyed watching this documentary to get a first impression of the idea itself and the effort involved. I had the chance to watch the german version of it online. But there is now another virtual <a href="https://purpose.film/screenings/">screening</a> offered by the <a href="https://permacultureeducationinstitute.org/permaculture-film-club/">Permacultur Film Club</a> on the 29th and 30th of March 2025. This screening is on a pay-as-you-like-and-can basis and includes a Q&A session with Kathrine Trebeck.</p> <p><a href="https://www.youtube.com/watch?v=9ybx2QGkZ-4">Trailer 1</a> and <a href="https://www.youtube.com/watch?v=sH8Y-gdR2K0">Trailer 2</a> are available on Youtube if you like to get a first impression.</p> </div> <p class="date"> <a href="http://sven.stormbind.net/blog/posts/misc_purpose_film/">20 March, 2025 03:04PM</a> </p> </div> </div> </div> <div class="channel"> <div id="http://sven.stormbind.net/blog/posts/k8s_deployment_prestop_sleep/" class="http://sven.stormbind.net/blog/posts/k8s_deployment_prestop_sleep/"> <div class="entry"> <h3 class="entry-title"> <a href="http://sven.stormbind.net/blog/posts/k8s_deployment_prestop_sleep/">k8s deployment build-in preStop sleep</a> </h3> <div class="content"> <p>Seems in the k8s world there are sufficient enough race conditions in shutting down pods and removing those from endpoint slices in time. Thus people started to do <a href="https://glasskube.dev/blog/kubernetes-zero-downtime-deployments-aws-eks/">all kind of workarounds</a> like adding a statically linked sleep binary to otherwise "distroless" and rather empty OCI images to just run a sleep command on shutdown before really shutting down. Or even base64 encoding the sleep binary and shipping it via configMap. Or whatever else. Eventually the situation was so severe that upstream decided to implement a <a href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/3960-pod-lifecycle-sleep-action/README.md#summary">sleep feature</a> in the deployment resource directly.</p> <p>In short it looks like this:</p> <pre><code>apiVersion: apps/v1 kind: Deployment metadata: name: foo spec: template: spec: lifecycle: preStop: sleep: seconds: 10 </code></pre> <p>Maybe highlighting that "feature" helps some more people to get rid of their own preStop sleep commands and make some deployments a tiny bit simpler.</p> </div> <p class="date"> <a href="http://sven.stormbind.net/blog/posts/k8s_deployment_prestop_sleep/">20 March, 2025 01:42PM</a> </p> </div> </div> </div> <h1>March 19, 2025</h1> <div class="channel"> <h2 class="planet-title"> <a href="https://blog.sirena.org.uk/" title="Technicalities">Mark Brown</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://blog.sirena.org.uk/seoul-trail-revamp/_hide\" onClick=\"exclude( 'https://blog.sirena.org.uk/seoul-trail-revamp/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://blog.sirena.org.uk/seoul-trail-revamp/_show\" style=\"display:none;\" onClick=\"show( 'https://blog.sirena.org.uk/seoul-trail-revamp/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://blog.sirena.org.uk/seoul-trail-revamp/" class="https://blog.sirena.org.uk/seoul-trail-revamp/"> <div class="entry"> <h3 class="entry-title"> <a href="https://blog.sirena.org.uk/seoul-trail-revamp/">Seoul Trail revamp</a> </h3> <div class="content"> <p>I regularly visit Seoul, and for the last couple of years I&aposve been doing segments from the <a href="https://english.seoul.go.kr/service/amusement/seoul-trail/01-seoul-trail/" rel="noreferrer">Seoul Trail</a>, a series of walks that add up to a 150km circuit around the outskirts of Seoul. If you like hiking I recommend it, it&aposs mostly through the hills and wooded areas surrounding the city or parks within the city and the bits I&aposve done thus far have mostly been very enjoyable. Everything is generally well signposted and easy to follow, with varying degrees of difficulty from completely flat paved roads to very hilly trails.</p><p>The trail had been divided into eight segments but just after I last visited the trail was reorganised into 21 smaller ones. This was very sensible, the original segments mostly being about 10-20km and taking 3-6 hours (with the notable exception of section 8, which was 36km) which can be a bit much (especially that section 8, or section 1 which had about 1km of ascent in it overall). It does complicate matters if you&aposre trying to keep track of what you&aposve done already though so I&aposve put together a quick table:</p> <table> <tbody><tr> <th>Original</th><th>Revised</th> </tr> <tr><td>1</td><td>1-3</td></tr> <tr><td>2</td><td>4-5</td></tr> <tr><td>3</td><td>6-8</td></tr> <tr><td>4</td><td>9-10</td></tr> <tr><td>5</td><td>11-12</td></tr> <tr><td>6</td><td>13-14</td></tr> <tr><td>7</td><td>15-16</td></tr> <tr><td>8</td><td>17-21</td></tr> </tbody></table> <p>This is all straightforward, the original segments had all been arranged to start and stop at metro stations (which I think explains the length of 8, the metro network is thin around Bukhansan what with it being an actual mountain) and the new segments are all straight subdivisions, but it&aposs handy to have it written down and I figured other people might find it useful.</p> </div> <p class="date"> <a href="https://blog.sirena.org.uk/seoul-trail-revamp/">19 March, 2025 12:18AM</a> by Mark Brown </p> </div> </div> </div> <h1>March 18, 2025</h1> <div class="channel"> <a href="https://mjg59.dreamwidth.org/"> <img class="face" src="heads/mjg59.png" width="69" height="85" alt="hackergotchi for Matthew Garrett" /> </a> <h2 class="planet-title"> <a href="https://mjg59.dreamwidth.org/" title="Matthew Garrett">Matthew Garrett</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://mjg59.dreamwidth.org/71188.html_hide\" onClick=\"exclude( 'https://mjg59.dreamwidth.org/71188.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://mjg59.dreamwidth.org/71188.html_show\" style=\"display:none;\" onClick=\"show( 'https://mjg59.dreamwidth.org/71188.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://mjg59.dreamwidth.org/71188.html" class="https://mjg59.dreamwidth.org/71188.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://mjg59.dreamwidth.org/71188.html">Failing upwards: the Twitter encrypted DM failure</a> </h3> <div class="content"> Almost two years ago, Twitter launched encrypted direct messages. I wrote about their technical implementation <a href="https://mjg59.dreamwidth.org/66791.html">at the time</a>, and to the best of my knowledge nothing has changed. The short story is that the actual <em>encryption</em> primitives used are entirely normal and fine - messages are encrypted using AES, and the AES keys are exchanged via NIST P-256 elliptic curve asymmetric keys. The asymmetric keys are each associated with a specific device or browser owned by a user, so when you send a message to someone you encrypt the AES key with all of their asymmetric keys and then each device or browser can decrypt the message again. As long as the keys are managed appropriately, this is infeasible to break.<br /><br />But how do you know what a user's keys are? I also wrote about this <a href="https://mjg59.dreamwidth.org/62598.html">last year</a> - key distribution is a hard problem. In the Twitter DM case, you ask Twitter's server, and if Twitter wants to intercept your messages they replace your key. The documentation for the feature <a href="https://help.x.com/en/using-x/encrypted-direct-messages">basically admits this</a> - if people with guns showed up there, they could very much compromise the protection in such a way that all future messages you sent were readable. It's also impossible to prove that they're not already doing this without every user verifying that the public keys Twitter hands out to other users correspond to the private keys they hold, something that Twitter provides no mechanism to do.<br /><br />This isn't the only weakness in the implementation. Twitter may not be able read the messages, but every encrypted DM is sent through exactly the same infrastructure as the unencrypted ones, so Twitter can see the time a message was sent, who it was sent to, and roughly how big it was. And because pictures and other attachments in Twitter DMs aren't sent in-line but are instead replaced with links, the implementation would encrypt the links but not the attachments - this is "solved" by simply blocking attachments in encrypted DMs. There's no forward secrecy - if a key is compromised it allows access to not only all new messages created with that key, but also all previous messages. If you log out of Twitter the keys are still stored by the browser, so if you can potentially be extracted and used to decrypt your communications. And there's no group chat support at all, which is more a functional restriction than a conceptual one.<br /><br />To be fair, these are hard problems to solve! <a href="https://signal.org">Signal</a> solves all of them, but Signal is the product of a large number of highly skilled experts in cryptography, and even so it's taken years to achieve all of this. When Elon announced the launch of encrypted DMs he indicated that new features would be developed quickly - he's since publicly mentioned the feature a grand total of <a href="https://x.com/elonmusk/status/1810131200939299254">once</a>, in which he mentioned further feature development that just didn't happen. None of the limitations mentioned in the documentation have been addressed in the 22 months since the feature was launched.<br /><br />Why? Well, it turns out that the feature was developed by a total of two engineers, neither of whom is still employed at Twitter. The tech lead for the feature was <a href="https://www.linkedin.com/in/stanleynetworks/">Christopher Stanley</a>, who was actually a SpaceX employee at the time. Since then he's ended up at DOGE, where he apparently <a href="https://x.com/maggieNYT/status/1901820644087472537">set off alarms when attempting to install Starlink</a>, and who today is apparently <a href="https://finance.yahoo.com/news/musk-ally-doge-member-stanley-013902235.html">being appointed to the board of Fannie Mae</a>, a government-backed mortgage company.<br /><br />Anyway. Use Signal.<br /><br /><img alt="comment count unavailable" height="12" src="https://www.dreamwidth.org/tools/commentcount?user=mjg59&ditemid=71188" style="vertical-align: middle;" width="30" /> comments </div> <p class="date"> <a href="https://mjg59.dreamwidth.org/71188.html">18 March, 2025 11:58PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="https://www.kvr.at/" title="Christian Kastner">Christian Kastner</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/_hide\" onClick=\"exclude( 'https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/_show\" style=\"display:none;\" onClick=\"show( 'https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/" class="https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/"> <div class="entry"> <h3 class="entry-title"> <a href="https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/">15th Anniversary of My First Debian Upload</a> </h3> <div class="content"> <p>Time flies! 15 years ago, on 2010-03-18, my first upload to the Debian archive was <a class="reference external" href="https://tracker.debian.org/news/246978/accepted-zd1211-firmware-22100-1-source-all">accepted</a>. Debian had replaced Windows as my primary OS in 2005, but it was only when I saw that package <a class="reference external" href="https://tracker.debian.org/pkg/zd1211-firmware">zd1211-firmware</a> had been orphaned that I thought of becoming a contributor. I owned a Zyxel G-202 USB WiFi fob that needed said firmware, and as is so often is with open-source software, I was going to scratch my own itch. Bart Martens thankfully helped me adopt the package, and sponsored my upload.</p> <p>I then joined Javier Fernández-Sanguino Peña as a cron maintainer and upstream, and also worked within the Debian Python Applications, Debian Python Modules, and Debian Science Teams, where Jakub Wilk and Yaroslav Halchenko were kind enough to mentor me and eventually support my application to become a Debian Maintainer.</p> <p>Life intervened, and I was mostly inactive in Debian for the next two years. Upon my return in 2014, I had Vincent Cheng to thank for sponsoring most of my newer work, and for eventually supporting my application to become a Debian Developer. It was around that time that I also attended my first DebConf, in <a class="reference external" href="https://debconf14.debconf.org/">Portland</a>, which remains one of my fondest memories. I had never been to an open-source software conference before, and DebConf14 really knocked it out of the park in so many ways.</p> <p>After another break, I returned in 2019 to work mostly on Python and machine learning libraries. In 2020, I finally completed a process that I had first started in 2012 but had never managed to finish before: converting cron from <a class="reference external" href="https://manpages.debian.org/unstable/dpkg-dev/dpkg-source.1.en.html#Format:_1.0">source format 1.0</a> (one big diff) to <a class="reference external" href="https://manpages.debian.org/unstable/dpkg-dev/dpkg-source.1.en.html#Format:_3.0_(quilt)">source format 3.0 (quilt)</a> (a series of patches). This was a process where I converted 25 years worth of organic growth into a minimal series of logically grouped changes (more <a class="reference external" href="https://sources.debian.org/src/cron/3.0pl1-137/debian/source-format-3.md/">here</a>). This was my white whale.</p> <p>In early 2023, shortly after the launch of ChatGPT which triggered an unprecedented AI boom, I started contributing to the Debian ROCm Team, where over the following year, I bootstrapped our CI at <a class="reference external" href="https://ci.rocm.debian.net">ci.rocm.debian.net</a>. Debian's current tooling lack a way to express dependencies on specific hardware other than CPU ISA, nor does it have the means to run autopkgtests using such hardware. To get autopkgtests to make use of AMD GPUs in QEMU VMs and in containers, I had to fork autopkgtest, debci, and a few other components, as well as create a fair share of new tooling for ourselves. This worked out pretty well, and the CI has grown to support 17 different AMD GPU architectures. I will share more on this in upcoming posts.</p> <p>I have mentioned a few contributors by name, but I have countless others to thank for collaborations over the years. It has been a wonderful experience, and I look forward to many years more.</p> </div> <p class="date"> <a href="https://www.kvr.at/posts/15th-anniversary-of-my-first-debian-upload/">18 March, 2025 11:16PM</a> by Christian Kastner </p> </div> </div> </div> <div class="channel"> <a href="http://dirk.eddelbuettel.com/blog"> <img class="face" src="heads/dirk.png" width="65" height="90" alt="hackergotchi for Dirk Eddelbuettel" /> </a> <h2 class="planet-title"> <a href="http://dirk.eddelbuettel.com/blog" title="Thinking inside the box">Dirk Eddelbuettel</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1_hide\" onClick=\"exclude( 'http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1_show\" style=\"display:none;\" onClick=\"show( 'http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1" class="http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1"> <div class="entry"> <h3 class="entry-title"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1">RcppArmadillo 14.4.0-1 on CRAN: New Upstream</a> </h3> <div class="content"> <p><img alt="armadillo image" src="http://dirk.eddelbuettel.com/images/armadillo_logo_two.png" style="float: left; margin: 10px 10px 10px 0;" /></p> <p><a href="https://arma.sourceforge.net/">Armadillo</a> is a powerful and expressive C++ template library for linear algebra and scientific computing. It aims towards a good balance between speed and ease of use, has a syntax deliberately close to Matlab, and is useful for algorithm development directly in C++, or quick conversion of research code into production environments. <a href="https://dirk.eddelbuettel.com/code/rcpp.armadillo.html">RcppArmadillo</a> integrates this library with the <a href="https://www.r-project.org">R</a> environment and language–and is widely used by (currently) 1234 other packages on <a href="https://cran.r-project.org">CRAN</a>, downloaded 38.8 million times (per the partial logs from the cloud mirrors of CRAN), and the <a href="https://doi.org/10.1016/j.csda.2013.02.005">CSDA paper</a> (<a href="https://cran.r-project.org/package=RcppArmadillo/vignettes/RcppArmadillo-intro.pdf">preprint / vignette</a>) by Conrad and myself has been cited 617 times according to Google Scholar.</p> <p><a href="https://conradsanderson.id.au/">Conrad</a> released a new minor version 14.4.0 last month. That was preceding by several extensive rounds of reverse-dependency checks covering the 1200+ packages at CRAN. We eventually narrowed the impact down to just eight packages, and I opened <a href="https://github.com/RcppCore/RcppArmadillo/issues/462">issue #462</a> to manage the transition along with ‘GitHub-only’ release 14.4.0-0 of <a href="https://github.com/RcppCore/RcppArmadillo">RcppArmadillo</a>. Several maintainers responded very promptly and updated within days – this is truly appreciated. Yesterday the last package updated at <a href="https://cran.r-project.org">CRAN</a> coinciding nicely with our planned / intended upload to <a href="https://cran.r-project.org">CRAN</a> one month after the release. So this new release, at version -1, is now on <a href="https://cran.r-project.org">CRAN</a>. It brings the usual number of small improvements to <a href="https://arma.sourceforge.net/">Armadillo</a> itself as well as updates to packaging.</p> <p>The changes since the last <a href="https://cran.r-project.org">CRAN</a> release are summarised below.</p> <blockquote> <h4 id="changes-in-rcpparmadillo-version-14.4.0-1-2025-03-17">Changes in RcppArmadillo version 14.4.0-1 (2025-03-17)</h4> <ul> <li><p>CRAN release having given a few packages time to catch-up to small upstream change as discussed and managed in <a href="https://github.com/RcppCore/RcppArmadillo/issues/462">#462</a></p></li> <li><p>Updated bibliography, and small edits to sparse matrix vignette</p></li> <li><p>Switched continuous integration action to r-ci with implicit bootstrap</p></li> </ul> <h4 id="changes-in-rcpparmadillo-version-14.4.0-0-2025-02-17-github-only">Changes in RcppArmadillo version 14.4.0-0 (2025-02-17) (GitHub Only)</h4> <ul> <li><p>Upgraded to Armadillo release 14.4.0 (Filtered Espresso)</p> <ul> <li><p>Faster handling of <code>pow()</code> and <code>square()</code> within <code>accu()</code> and <code>sum()</code> expressions</p></li> <li><p>Faster <code>sort()</code> and <code>sort_index()</code> for complex matrices</p></li> <li><p>Expanded the field class with <code>.reshape()</code> and <code>.resize()</code> member functions</p></li> <li><p>More efficient handling of compound expressions by <code>sum()</code>, <code>reshape()</code>, <code>trans()</code></p></li> <li><p>Better detection of vector expressions by <code>pow()</code>, <code>imag()</code>, <code>conj()</code></p></li> </ul></li> <li><p>The package generator helper function now supports additional DESCRIPTIONs</p></li> <li><p>This release revealed a need for very minor changes for a handful reverse-dependency packages which will be organized via GitHub issue tracking</p></li> </ul> </blockquote> <p>Courtesy of my <a href="https://dirk.eddelbuettel.com/cranberries/">CRANberries</a>, there is a <a href="https://dirk.eddelbuettel.com/cranberries/2025/03/18/#RcppArmadillo_14.4.0-1">diffstat report</a> relative to previous release. More detailed information is on the <a href="https://dirk.eddelbuettel.com/code/rcpp.armadillo.html">RcppArmadillo page</a>. Questions, comments etc should go to the <a href="https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel">rcpp-devel mailing list</a> off the <a href="https://r-forge.r-project.org/projects/rcpp/">Rcpp R-Forge</a> page.</p> <p style="font-size: 80%; font-style: italic;"> This post by <a href="https://dirk.eddelbuettel.com">Dirk Eddelbuettel</a> originated on his <a href="https://dirk.eddelbuettel.com/blog/">Thinking inside the box</a> blog. If you like this or other open-source work I do, you can <a href="https://github.com/sponsors/eddelbuettel">sponsor me at GitHub</a>. </p><p></p> </div> <p class="date"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/18#rcpparmadillo_14.4.0-1">18 March, 2025 08:02PM</a> </p> </div> </div> </div> <div class="channel"> <a href="https://blogops.mixinet.net/"> <img class="face" src="heads/sto.png" width="65" height="85" alt="hackergotchi for Sergio Talens-Oliag" /> </a> <h2 class="planet-title"> <a href="https://blogops.mixinet.net/" title="Mixinet BlogOps">Sergio Talens-Oliag</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/_hide\" onClick=\"exclude( 'https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/_show\" style=\"display:none;\" onClick=\"show( 'https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/" class="https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/"> <div class="entry"> <h3 class="entry-title"> <a href="https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/">Using actions to build this site</a> </h3> <div class="content"> <p>As promised on my previous <a href="https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/" rel="noopener" target="_blank">post</a>, on this entry I’ll explain how I’ve set up forgejo actions on the source repository of this site to build it using a runner instead of doing it on the public server using a webhook to trigger the operation.</p> <section class="doc-section level-1"><h2 id="_setting_up_the_system">Setting up the system</h2><p>The first thing I’ve done is to disable the forgejo webhook call that was used to publish the site, as I don’t want to run it anymore.</p> <aside class="admonition-block note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>For now I’ve just removed the <em>Active</em> flag from the webhook, just in case I want to use it again in the future.</p> <p>I’ve left the system based on the <code>json2file</code> server running as it does nothing if no webhook is called, if we want to use it again it would be a good idea to disable actions to avoid conflicts if something is pushed, but it can be executed manually if needed and nothing will break, as both systems use the same directories to publish things).</p></aside> <p>After that I added a new workflow to the repository that does the following things:</p> <div class="ulist"><ul><li>build the site using my <a href="https://forgejo.mixinet.net/oci/images/src/branch/main/hugo-adoc/Dockerfile" rel="noopener" target="_blank">hugo-adoc</a> image.</li><li>push the result to a branch that contains the generated site (we do this because the server is already configured to work with the git repository and we can use force pushes to keep only the last version of the site, removing the need of extra code to manage package uploads and removals).</li><li>uses <code>curl</code> to send a notification to an instance of the <a href="https://github.com/adnanh/webhook" rel="noopener" target="_blank">webhook</a> server installed on the remote server that triggers a script that updates the site using the git branch.</li></ul></div> <aside class="admonition-block note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>As explained on my original post on the <a href="https://blogops.mixinet.net/posts/new_blog_config/#_production_setup" rel="noopener" target="_blank">production setup</a> section, I could have used the <code>json2file</code> server to process the notification, but I’ve decided to use the <code>webhook</code> server instead because it is simpler to set up and allows me to show a different approach to the same problem.</p> <p>The script that updates the site is executed by a user that has permissions to clone the repository using a ssh key.</p></aside></section> <section class="doc-section level-1"><h2 id="_setting_up_the_webhook_service">Setting up the <code>webhook</code> service</h2><p>On the server machine we have installed and configured the <code>webhook</code> service to run a script that updates the site.</p> <p>To install the application and setup the configuration we have used the following script:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="c">#!/bin/sh</span> <span class="nb">set</span> <span class="nt">-e</span> <span class="c"># ---------</span> <span class="c"># VARIABLES</span> <span class="c"># ---------</span> <span class="nv">ARCH</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span>dpkg <span class="nt">--print-architecture</span><span class="si">)</span><span class="s2">"</span> <span class="nv">WEBHOOK_VERSION</span><span class="o">=</span><span class="s2">"2.8.2"</span> <span class="nv">DOWNLOAD_URL</span><span class="o">=</span><span class="s2">"https://github.com/adnanh/webhook/releases/download"</span> <span class="nv">WEBHOOK_TGZ_URL</span><span class="o">=</span><span class="s2">"</span><span class="nv">$DOWNLOAD_URL</span><span class="s2">/</span><span class="nv">$WEBHOOK_VERSION</span><span class="s2">/webhook-linux-</span><span class="nv">$ARCH</span><span class="s2">.tar.gz"</span> <span class="nv">WEBHOOK_SERVICE_NAME</span><span class="o">=</span><span class="s2">"webhook"</span> <span class="c"># Files</span> <span class="nv">WEBHOOK_SERVICE_FILE</span><span class="o">=</span><span class="s2">"/etc/systemd/system/</span><span class="nv">$WEBHOOK_SERVICE_NAME</span><span class="s2">.service"</span> <span class="nv">WEBHOOK_SOCKET_FILE</span><span class="o">=</span><span class="s2">"/etc/systemd/system/</span><span class="nv">$WEBHOOK_SERVICE_NAME</span><span class="s2">.socket"</span> <span class="nv">WEBHOOK_TML_TEMPLATE</span><span class="o">=</span><span class="s2">"/srv/blogops/action/webhook.yml.envsubst"</span> <span class="nv">WEBHOOK_YML</span><span class="o">=</span><span class="s2">"/etc/webhook.yml"</span> <span class="c"># Config file values</span> <span class="nv">WEBHOOK_USER</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-u</span><span class="si">)</span><span class="s2">"</span> <span class="nv">WEBHOOK_GROUP</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-g</span><span class="si">)</span><span class="s2">"</span> <span class="nv">WEBHOOK_LISTEN_STREAM</span><span class="o">=</span><span class="s2">"172.31.31.1:4444"</span> <span class="c"># ----</span> <span class="c"># MAIN</span> <span class="c"># ----</span> <span class="c"># Install binary from releases (on Debian only version 2.8.0 is available, but</span> <span class="c"># I need the 2.8.2 version to support the systemd activation mode).</span> curl <span class="nt">-fsSL</span> <span class="nt">-o</span> <span class="s2">"/tmp/webhook.tgz"</span> <span class="s2">"</span><span class="nv">$WEBHOOK_TGZ_URL</span><span class="s2">"</span> <span class="nb">tar</span> <span class="nt">-C</span> /tmp <span class="nt">-xzf</span> /tmp/webhook.tgz <span class="nb">sudo install</span> <span class="nt">-m</span> 755 <span class="s2">"/tmp/webhook-linux-</span><span class="nv">$ARCH</span><span class="s2">/webhook"</span> /usr/local/bin/webhook <span class="nb">rm</span> <span class="nt">-rf</span> <span class="s2">"/tmp/webhook-linux-</span><span class="nv">$ARCH</span><span class="s2">"</span> /tmp/webhook.tgz <span class="c"># Service file</span> <span class="nb">sudo </span>sh <span class="nt">-c</span> <span class="s2">"cat >'</span><span class="nv">$WEBHOOK_SERVICE_FILE</span><span class="s2">'"</span> <span class="o"><<</span><span class="no">EOF</span><span class="sh"> [Unit] Description=Webhook server [Service] Type=exec ExecStart=webhook -nopanic -hooks </span><span class="nv">$WEBHOOK_YML</span><span class="sh"> User=</span><span class="nv">$WEBHOOK_USER</span><span class="sh"> Group=</span><span class="nv">$WEBHOOK_GROUP</span><span class="sh"> </span><span class="no">EOF </span><span class="c"># Socket config</span> <span class="nb">sudo </span>sh <span class="nt">-c</span> <span class="s2">"cat >'</span><span class="nv">$WEBHOOK_SOCKET_FILE</span><span class="s2">'"</span> <span class="o"><<</span><span class="no">EOF</span><span class="sh"> [Unit] Description=Webhook server socket [Socket] # Set FreeBind to listen on missing addresses (the VPN can be down sometimes) FreeBind=true # Set ListenStream to the IP and port you want to listen on ListenStream=</span><span class="nv">$WEBHOOK_LISTEN_STREAM</span><span class="sh"> [Install] WantedBy=multi-user.target </span><span class="no">EOF </span><span class="c"># Config file</span> <span class="nv">BLOGOPS_TOKEN</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span>uuid<span class="si">)</span><span class="s2">"</span> <span class="se">\</span> envsubst <<span class="s2">"</span><span class="nv">$WEBHOOK_TML_TEMPLATE</span><span class="s2">"</span> | <span class="nb">sudo </span>sh <span class="nt">-c</span> <span class="s2">"cat ></span><span class="nv">$WEBHOOK_YML</span><span class="s2">"</span> <span class="nb">chmod </span>0640 <span class="s2">"</span><span class="nv">$WEBHOOK_YML</span><span class="s2">"</span> chwon <span class="s2">"</span><span class="nv">$WEBHOOK_USER</span><span class="s2">:</span><span class="nv">$WEBHOOK_GROUP</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$WEBHOOK_YML</span><span class="s2">"</span> <span class="c"># Restart and enable service</span> <span class="nb">sudo </span>systemctl daemon-reload <span class="nb">sudo </span>systemctl stop <span class="s2">"</span><span class="nv">$WEBHOOK_SERVICE_NAME</span><span class="s2">.socket"</span> <span class="nb">sudo </span>systemctl start <span class="s2">"</span><span class="nv">$WEBHOOK_SERVICE_NAME</span><span class="s2">.socket"</span> <span class="nb">sudo </span>systemctl <span class="nb">enable</span> <span class="s2">"</span><span class="nv">$WEBHOOK_SERVICE_NAME</span><span class="s2">.socket"</span> <span class="c"># ----</span> <span class="c"># vim: ts=2:sw=2:et:ai:sts=2</span></code></pre></div> <p>As seen on the code, we’ve installed the application using a binary from the project repository instead of a package because we needed the latest version of the application to use <code>systemd</code> with socket activation.</p> <p>The configuration file template is the following one:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="pi">-</span> <span class="na">id</span><span class="pi">:</span> <span class="s2">"</span><span class="s">update-blogops"</span> <span class="na">execute-command</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/srv/blogops/action/bin/update-blogops.sh"</span> <span class="na">command-working-directory</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/srv/blogops"</span> <span class="na">trigger-rule</span><span class="pi">:</span> <span class="na">match</span><span class="pi">:</span> <span class="na">type</span><span class="pi">:</span> <span class="s2">"</span><span class="s">value"</span> <span class="na">value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">$BLOGOPS_TOKEN"</span> <span class="na">parameter</span><span class="pi">:</span> <span class="na">source</span><span class="pi">:</span> <span class="s2">"</span><span class="s">header"</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">X-Blogops-Token"</span></code></pre></div> <p>The version on <code>/etc/webhook.yml</code> has the <code>BLOGOPS_TOKEN</code> adjusted to a random value that has to exported as a secret on the forgejo project (see later).</p> <aside class="admonition-block note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>As we are going to be connecting to this server using a VPN we don’t need to enable TLS on the <code>webhook</code> server, but if we want to do it we just need to change the <code>/etc/systemd/system/webhook.service</code> file to include the <code>-secure</code>, <code>-cert</code> and <code>-key</code> options with the right paths to the certificate and key files on the <code>ExecStart</code> line:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="nn">[Service]</span> <span class="py">ExecStart</span><span class="p">=</span><span class="s">webhook -nopanic -hooks /etc/webhook.yaml </span><span class="se">\ </span> <span class="s">-secure -cert PATH_TO_WEBHOOK_CRT -key PATH_TO_WEBHOOK_KEY</span></code></pre></div></aside> <p>Once the service is started each time the action is executed the <code>webhook</code> daemon will get a notification and will run the following <code>update-blogops.sh</code> script to publish the updated version of the site:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="c">#!/bin/sh</span> <span class="nb">set</span> <span class="nt">-e</span> <span class="c"># ---------</span> <span class="c"># VARIABLES</span> <span class="c"># ---------</span> <span class="c"># Values</span> <span class="nv">REPO_URL</span><span class="o">=</span><span class="s2">"ssh://git@forgejo.mixinet.net/mixinet/blogops.git"</span> <span class="nv">REPO_BRANCH</span><span class="o">=</span><span class="s2">"html"</span> <span class="nv">REPO_DIR</span><span class="o">=</span><span class="s2">"public"</span> <span class="nv">MAIL_PREFIX</span><span class="o">=</span><span class="s2">"[BLOGOPS-UPDATE-ACTION] "</span> <span class="c"># Address that gets all messages, leave it empty if not wanted</span> <span class="nv">MAIL_TO_ADDR</span><span class="o">=</span><span class="s2">"blogops@mixinet.net"</span> <span class="c"># Directories</span> <span class="nv">BASE_DIR</span><span class="o">=</span><span class="s2">"/srv/blogops"</span> <span class="nv">PUBLIC_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BASE_DIR</span><span class="s2">/</span><span class="nv">$REPO_DIR</span><span class="s2">"</span> <span class="nv">NGINX_BASE_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BASE_DIR</span><span class="s2">/nginx"</span> <span class="nv">PUBLIC_HTML_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$NGINX_BASE_DIR</span><span class="s2">/public_html"</span> <span class="nv">ACTION_BASE_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BASE_DIR</span><span class="s2">/action"</span> <span class="nv">ACTION_LOG_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$ACTION_BASE_DIR</span><span class="s2">/log"</span> <span class="c"># Files</span> <span class="nv">OUTPUT_BASENAME</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d-%H%M%S.%N<span class="si">)</span><span class="s2">"</span> <span class="nv">ACTION_LOGFILE_PATH</span><span class="o">=</span><span class="s2">"</span><span class="nv">$ACTION_LOG_DIR</span><span class="s2">/</span><span class="nv">$OUTPUT_BASENAME</span><span class="s2">.log"</span> <span class="c"># ---------</span> <span class="c"># Functions</span> <span class="c"># ---------</span> action_log<span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">date</span> <span class="nt">-R</span><span class="si">)</span><span class="s2"> </span><span class="nv">$*</span><span class="s2">"</span> <span class="o">>></span><span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> <span class="o">}</span> action_check_directories<span class="o">()</span> <span class="o">{</span> <span class="k">for </span>_d <span class="k">in</span> <span class="s2">"</span><span class="nv">$ACTION_BASE_DIR</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$ACTION_LOG_DIR</span><span class="s2">"</span><span class="p">;</span> <span class="k">do</span> <span class="o">[</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$_d</span><span class="s2">"</span> <span class="o">]</span> <span class="o">||</span> <span class="nb">mkdir</span> <span class="s2">"</span><span class="nv">$_d</span><span class="s2">"</span> <span class="k">done</span> <span class="o">}</span> action_clean_directories<span class="o">()</span> <span class="o">{</span> <span class="c"># Try to remove empty dirs</span> <span class="k">for </span>_d <span class="k">in</span> <span class="s2">"</span><span class="nv">$ACTION_LOG_DIR</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$ACTION_BASE_DIR</span><span class="s2">"</span><span class="p">;</span> <span class="k">do if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$_d</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span><span class="nb">rmdir</span> <span class="s2">"</span><span class="nv">$_d</span><span class="s2">"</span> 2>/dev/null <span class="o">||</span> <span class="nb">true </span><span class="k">fi done</span> <span class="o">}</span> mail_success<span class="o">()</span> <span class="o">{</span> <span class="nv">to_addr</span><span class="o">=</span><span class="s2">"</span><span class="nv">$MAIL_TO_ADDR</span><span class="s2">"</span> <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$to_addr</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span><span class="nv">subject</span><span class="o">=</span><span class="s2">"OK - updated blogops site"</span> mail <span class="nt">-s</span> <span class="s2">"</span><span class="k">${</span><span class="nv">MAIL_PREFIX</span><span class="k">}${</span><span class="nv">subject</span><span class="k">}</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$to_addr</span><span class="s2">"</span> <<span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> <span class="k">fi</span> <span class="o">}</span> mail_failure<span class="o">()</span> <span class="o">{</span> <span class="nv">to_addr</span><span class="o">=</span><span class="s2">"</span><span class="nv">$MAIL_TO_ADDR</span><span class="s2">"</span> <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$to_addr</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span><span class="nv">subject</span><span class="o">=</span><span class="s2">"KO - failed to update blogops site"</span> mail <span class="nt">-s</span> <span class="s2">"</span><span class="k">${</span><span class="nv">MAIL_PREFIX</span><span class="k">}${</span><span class="nv">subject</span><span class="k">}</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$to_addr</span><span class="s2">"</span> <<span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> <span class="k">fi </span><span class="nb">exit </span>1 <span class="o">}</span> <span class="c"># ----</span> <span class="c"># MAIN</span> <span class="c"># ----</span> <span class="nv">ret</span><span class="o">=</span><span class="s2">"0"</span> <span class="c"># Check directories</span> action_check_directories <span class="c"># Go to the base directory</span> <span class="nb">cd</span> <span class="s2">"</span><span class="nv">$BASE_DIR</span><span class="s2">"</span> <span class="c"># Remove the old build dir if present</span> <span class="k">if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$PUBLIC_DIR</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span><span class="nb">rm</span> <span class="nt">-rf</span> <span class="s2">"</span><span class="nv">$PUBLIC_DIR</span><span class="s2">"</span> <span class="k">fi</span> <span class="c"># Update the repository checkout</span> action_log <span class="s2">"Updating the repository checkout"</span> git fetch <span class="nt">--all</span> <span class="o">>></span><span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> 2>&1 <span class="o">||</span> <span class="nv">ret</span><span class="o">=</span><span class="s2">"</span><span class="nv">$?</span><span class="s2">"</span> <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$ret</span><span class="s2">"</span> <span class="nt">-ne</span> <span class="s2">"0"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span>action_log <span class="s2">"Failed to update the repository checkout"</span> mail_failure <span class="k">fi</span> <span class="c"># Get it from the repo branch & extract it</span> action_log <span class="s2">"Downloading and extracting last site version using 'git archive'"</span> git archive <span class="nt">--remote</span><span class="o">=</span><span class="s2">"</span><span class="nv">$REPO_URL</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$REPO_BRANCH</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$REPO_DIR</span><span class="s2">"</span> <span class="se">\</span> | <span class="nb">tar </span>xf - <span class="o">>></span><span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> 2>&1 <span class="o">||</span> <span class="nv">ret</span><span class="o">=</span><span class="s2">"</span><span class="nv">$?</span><span class="s2">"</span> <span class="c"># Fail if public dir was missing</span> <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$ret</span><span class="s2">"</span> <span class="nt">-ne</span> <span class="s2">"0"</span> <span class="o">]</span> <span class="o">||</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$PUBLIC_DIR</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span>action_log <span class="s2">"Failed to download or extract site"</span> mail_failure <span class="k">fi</span> <span class="c"># Remove old public_html copies</span> action_log <span class="s1">'Removing old site versions, if present'</span> find <span class="nv">$NGINX_BASE_DIR</span> <span class="nt">-mindepth</span> 1 <span class="nt">-maxdepth</span> 1 <span class="nt">-name</span> <span class="s1">'public_html-*'</span> <span class="nt">-type</span> d <span class="se">\</span> <span class="nt">-exec</span> <span class="nb">rm</span> <span class="nt">-rf</span> <span class="o">{}</span> <span class="se">\;</span> <span class="o">>></span><span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> 2>&1 <span class="o">||</span> <span class="nv">ret</span><span class="o">=</span><span class="s2">"</span><span class="nv">$?</span><span class="s2">"</span> <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$ret</span><span class="s2">"</span> <span class="nt">-ne</span> <span class="s2">"0"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span>action_log <span class="s2">"Removal of old site versions failed"</span> mail_failure <span class="k">fi</span> <span class="c"># Switch site directory</span> <span class="nv">TS</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">date</span> +%Y%m%d-%H%M%S<span class="si">)</span><span class="s2">"</span> <span class="k">if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$PUBLIC_HTML_DIR</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span>action_log <span class="s2">"Moving '</span><span class="nv">$PUBLIC_HTML_DIR</span><span class="s2">' to '</span><span class="nv">$PUBLIC_HTML_DIR</span><span class="s2">-</span><span class="nv">$TS</span><span class="s2">'"</span> <span class="nb">mv</span> <span class="s2">"</span><span class="nv">$PUBLIC_HTML_DIR</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$PUBLIC_HTML_DIR</span><span class="s2">-</span><span class="nv">$TS</span><span class="s2">"</span> <span class="o">>></span><span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> 2>&1 <span class="o">||</span> <span class="nv">ret</span><span class="o">=</span><span class="s2">"</span><span class="nv">$?</span><span class="s2">"</span> <span class="k">fi if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$ret</span><span class="s2">"</span> <span class="nt">-eq</span> <span class="s2">"0"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span>action_log <span class="s2">"Moving '</span><span class="nv">$PUBLIC_DIR</span><span class="s2">' to '</span><span class="nv">$PUBLIC_HTML_DIR</span><span class="s2">'"</span> <span class="nb">mv</span> <span class="s2">"</span><span class="nv">$PUBLIC_DIR</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$PUBLIC_HTML_DIR</span><span class="s2">"</span> <span class="o">>></span><span class="s2">"</span><span class="nv">$ACTION_LOGFILE_PATH</span><span class="s2">"</span> 2>&1 <span class="o">||</span> <span class="nv">ret</span><span class="o">=</span><span class="s2">"</span><span class="nv">$?</span><span class="s2">"</span> <span class="k">fi if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$ret</span><span class="s2">"</span> <span class="nt">-ne</span> <span class="s2">"0"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then </span>action_log <span class="s2">"Site switch failed"</span> mail_failure <span class="k">else </span>action_log <span class="s2">"Site updated successfully"</span> mail_success <span class="k">fi</span> <span class="c"># ----</span> <span class="c"># vim: ts=2:sw=2:et:ai:sts=2</span></code></pre></div></section> <section class="doc-section level-1"><h2 id="_the_hugo_adoc_workflow">The <code>hugo-adoc</code> workflow</h2><p>The workflow is defined in the <code>.forgejo/workflows/hugo-adoc.yml</code> file and looks like this:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">hugo-adoc</span> <span class="c1"># Run this job on push events to the main branch</span> <span class="na">on</span><span class="pi">:</span> <span class="na">push</span><span class="pi">:</span> <span class="na">branches</span><span class="pi">:</span> <span class="pi">-</span> <span class="s1">'</span><span class="s">main'</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">build-and-push</span><span class="pi">:</span> <span class="na">if</span><span class="pi">:</span> <span class="s">${{ vars.BLOGOPS_WEBHOOK_URL != '' && secrets.BLOGOPS_TOKEN != '' }}</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">docker</span> <span class="na">container</span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">forgejo.mixinet.net/oci/hugo-adoc:latest</span> <span class="c1"># Allow the job to write to the repository (not really needed on forgejo)</span> <span class="na">permissions</span><span class="pi">:</span> <span class="na">contents</span><span class="pi">:</span> <span class="s">write</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout the repo</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span> <span class="na">with</span><span class="pi">:</span> <span class="na">submodules</span><span class="pi">:</span> <span class="s1">'</span><span class="s">true'</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build the site</span> <span class="na">shell</span><span class="pi">:</span> <span class="s">sh</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">rm -rf public</span> <span class="s">hugo</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Push compiled site to html branch</span> <span class="na">shell</span><span class="pi">:</span> <span class="s">sh</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s"># Set the git user</span> <span class="s">git config --global user.email "blogops@mixinet.net"</span> <span class="s">git config --global user.name "BlogOps"</span> <span class="s"># Create a new orphan branch called html (it was not pulled by the</span> <span class="s"># checkout step)</span> <span class="s">git switch --orphan html</span> <span class="s"># Add the public directory to the branch</span> <span class="s">git add public</span> <span class="s"># Commit the changes</span> <span class="s">git commit --quiet -m "Updated site @ $(date -R)" public</span> <span class="s"># Push the changes to the html branch</span> <span class="s">git push origin html --force</span> <span class="s"># Switch back to the main branch</span> <span class="s">git switch main</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Call the blogops update webhook endpoint</span> <span class="na">shell</span><span class="pi">:</span> <span class="s">sh</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">HEADER="X-Blogops-Token: ${{ secrets.BLOGOPS_TOKEN }}"</span> <span class="s">curl --fail -k -H "$HEADER" ${{ vars.BLOGOPS_WEBHOOK_URL }}</span></code></pre></div> <p>The only relevant thing is that we have to add the <code>BLOGOPS_TOKEN</code> variable to the project secrets (its value is the one included on the <code>/etc/webhook.yml</code> file created when installing the <code>webhook</code> service) and the <code>BLOGOPS_WEBHOOK_URL</code> project variable (its value is the URL of the <code>webhook</code> server, in my case <code><a class="bare" href="http://172.31.31.1:4444/hooks/update-blogops">http://172.31.31.1:4444/hooks/update-blogops</a></code>); note that the job includes the <code>-k</code> flag on the <code>curl</code> command just in case I end up using TLS on the <code>webhook</code> server in the future, as discussed previously.</p></section> <section class="doc-section level-1"><h2 id="_conclusion">Conclusion</h2><p>Now that I have forgejo actions on my server I no longer need to build the site on the public server as I did initially, a good thing when the server is a small OVH VPS that only runs a couple of containers and a web server directly on the host.</p> <p>I’m still using a notification system to make the server run a script to update the site because that way the forgejo server does not need access to the remote machine shell, only the <code>webhook</code> server which, IMHO, is a more secure setup.</p></section> </div> <p class="date"> <a href="https://blogops.mixinet.net/posts/forgejo/using_actions_to_build_this_site/">18 March, 2025 07:00PM</a> </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="http://www.hungry.com/~pere/blog/" title="Petter Reinholdtsen - Entries tagged english">Petter Reinholdtsen</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html_hide\" onClick=\"exclude( 'http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html_show\" style=\"display:none;\" onClick=\"show( 'http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html" class="http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html"> <div class="entry"> <h3 class="entry-title"> <a href="http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html">New theora release 1.2.0beta1 after almost 15 years</a> </h3> <div class="content"> <p>When I a few days ago discovered that a security problem reported against the theora library last year was still not fixed, and because I was already up to speed on Xiph development, I decided it was time to wrap up a new theora release. This new release was tagged in <a href="https://gitlab.xiph.org/xiph/theora">the Xiph gitlab theora instance</a> Saturday. You can fetch the new release from <a href="https://xiph.org/theora/">the Theora home page</a>.</p> <p>The list of changes since The 1.2.0alpha1 release from the CHANGES file in the tarball look like this:</p> <blockquote> <p>libteora 1.2.0beta1 (2025 March 15)</p> <ul> <li>Bumped minor SONAME versions as methods changed constness of arguments.</li> <li>Updated libogg dependency to version 1.3.4 for ogg_uint64_t.</li> <li>Updated doxygen setup.</li> <li>Updated autotools setup and support scripts (#1467 #1800 #1987 #2318 #2320).</li> <li>Added support for RISC OS.</li> <li>Fixed mingw build (#2141).</li> <li>Improved ARM support.</li> <li>Converted SCons setup to work with Python 3.</li> <li>Introduced new configure options --enable-mem-constraint and --enable-gcc-sanitizers.</li> <li>Fixed all known compiler warnings and errors from gcc and clang.</li> <li>Improved examples for stability and correctness.</li> <li>Variuos speed, bug fixes and code quality improvements.</li> <li>Fixed build problem with Visual Studio (#2317).</li> <li>Avoids undefined bit shift of signed numbers (#2321, #2322).</li> <li>Avoids example encoder crash on bogus audio input (#2305).</li> <li>Fixed musl linking issue with asm enabled (#2287).</li> <li>Fixed some broken clamping in rate control (#2229).</li> <li>Added NULL check _tc and _setup even for data packets (#2279).</li> <li>Fixed mismatched oc_mb_fill_cmapping11 signature (#2068).</li> <li>Updated the documentation for theora_encode_comment() (#726).</li> <li>Adjusted build to Only link libcompat with dump_video (#1587).</li> <li>Corrected an operator precedence error in the visualization code (#1751).</li> <li>Fixed two spelling errors in the comments (#1804).</li> <li>Avoid negative bit shift operation in huffdec.c (CVE-2024-56431).</li> <li>Improved library documentation and specification text.</li> <li>Adjusted library dependencies so libtheoraenc do not depend on libtheoradec.</li> <li>Handle fallout from CVE-2017-14633 in libvorbis, check return value in encoder_example and transcoder_example.</li> </ul> </blockquote> <p>There are a few bugs still being investigated, and my plan is to wrap up a final 1.2.0 release two weekends from now.</p> <p>As usual, if you use Bitcoin and want to show your support of my activities, please send Bitcoin donations to my address <b><a>15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b</a></b>.</p> </div> <p class="date"> <a href="http://www.hungry.com/~pere/blog/New_theora_release_1_2_0beta1_after_almost_15_years.html">18 March, 2025 07:30AM</a> </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="http://notes.secretsauce.net" title="Dima Kogan">Dima Kogan</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html_hide\" onClick=\"exclude( 'http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html_show\" style=\"display:none;\" onClick=\"show( 'http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html" class="http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html"> <div class="entry"> <h3 class="entry-title"> <a href="http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html">Eigen macro specializations crashes</a> </h3> <div class="content"> <p> There's an issue in the <a href="https://eigen.tuxfamily.org/index.php?title=Main_Page">Eigen linear algebra library</a> where linking together objects compiled with different flags causes the resulting binary to crash. Some details are written-up in <a href="https://www.mail-archive.com/debian-science@lists.debian.org/msg13672.html">this mailing list thread</a>. </p> <p> I just encountered a situation where a large application sometimes crashes for unknown reasons, and needed a method to determine whether this Eigen issue could be the cause. I ended up doing this by using the DWARF data to see if the linked binary contains the different incompatible flavors of <code>malloc</code> / <code>free</code> or not. </p> <p> I downloaded the <a href="https://www.mail-archive.com/debian-science@lists.debian.org/msg13710.html">small demo program showing the problem</a>. I built it: </p> <div class="org-src-container"> <pre class="src src-sh"><span style="color: #cdcd00;">CCXXXFLAGS</span>=-g make </pre> </div> <p> Here if you run <code>./main</code>, the bug is triggered, and a crash occurs. I looked at the debug info for the code in question: </p> <div class="org-src-container"> <pre class="src src-sh"><span style="color: #00cdcd; font-weight: bold;">for</span> o (main lib.so) { <span style="color: #0000ee; font-weight: bold;">echo</span> <span style="color: #00cd00;">"======== $o"</span>; readelf --debug-dump=decodedline $<span style="color: #cdcd00;">o</span> <span style="color: #00cd00;">\</span> | awk <span style="color: #00cd00;">\</span> <span style="color: #00cd00;">'$1 ~ /^Memory.h/</span> <span style="color: #00cd00;"> {</span> <span style="color: #00cd00;"> if(180 <= $2 && $2 <= 186) {</span> <span style="color: #00cd00;"> have["malloc_glibc"]=1</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> if(188 == $2) {</span> <span style="color: #00cd00;"> have["malloc_handmade"]=1</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> if(201 <= $2 && $2 <= 204) {</span> <span style="color: #00cd00;"> have["free_glibc"]=1</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> if(206 == $2) {</span> <span style="color: #00cd00;"> have["free_handmade"]=1</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> END</span> <span style="color: #00cd00;"> {</span> <span style="color: #00cd00;"> for (var in have) {</span> <span style="color: #00cd00;"> print(var);</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> }'</span> } </pre> </div> <p> It says: </p> <pre class="example">======== main free_handmade ======== lib.so malloc_glibc free_glibc </pre> <p> Here I looked at <code>main</code> and <code>lib.so</code> (the build products from this little demo). In a real case you'd look at every shared library linked into the binary and the binary itself. On my machine <code>/usr/include/eigen3/Eigen/src/Core/util/Memory.h</code> looks like this, starting on line 174: </p> <pre class="example">174 EIGEN_DEVICE_FUNC inline void* aligned_malloc(std::size_t size) 175 { 176 check_that_malloc_is_allowed(); 177 178 void *result; 179 #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED 180 181 EIGEN_USING_STD(malloc) 182 result = malloc(size); 183 184 #if EIGEN_DEFAULT_ALIGN_BYTES==16 185 eigen_assert((size<16 || (std::size_t(result)%16)==0) && "System's malloc returned an unaligned pointer. Compile with EIGEN_MALLOC_ALREADY_ALIGNED=0 to fallback to handmade aligned memory allocator."); 186 #endif 187 #else 188 result = handmade_aligned_malloc(size); 189 #endif 190 191 if(!result && size) 192 throw_std_bad_alloc(); 193 194 return result; 195 } 196 197 /** \internal Frees memory allocated with aligned_malloc. */ 198 EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr) 199 { 200 #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED 201 202 EIGEN_USING_STD(free) 203 free(ptr); 204 205 #else 206 handmade_aligned_free(ptr); 207 #endif 208 } </pre> <p> The above <code>awk</code> script looks at the two malloc paths and the two free paths, and we can clearly see that it only ever calls <code>malloc_glibc()</code>, but has both flavors of <code>free()</code>. So this can crash. We want to see that the whole executable (shared libraries and all) should only have one type of <code>malloc()</code> and <code>free()</code>, and that would guarantee no crashing. </p> <p> There are a more functions in that header that should be instrumented (<code>realloc()</code> for instance) and the different alignment paths should be instrumented similarly (as described in the mailing list thread above), but here we see that this technique works. </p> </div> <p class="date"> <a href="http://notes.secretsauce.net/notes/2025/03/17_eigen-macro-specializations-crashes.html">18 March, 2025 03:52AM</a> by Dima Kogan </p> </div> </div> </div> <h1>March 17, 2025</h1> <div class="channel"> <a href="https://blogops.mixinet.net/"> <img class="face" src="heads/sto.png" width="65" height="85" alt="hackergotchi for Sergio Talens-Oliag" /> </a> <h2 class="planet-title"> <a href="https://blogops.mixinet.net/" title="Mixinet BlogOps">Sergio Talens-Oliag</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/_hide\" onClick=\"exclude( 'https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/_show\" style=\"display:none;\" onClick=\"show( 'https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/" class="https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/"> <div class="entry"> <h3 class="entry-title"> <a href="https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/">Configuring forgejo actions</a> </h3> <div class="content"> <p>Last week I decided I wanted to try out <a href="https://forgejo.org/docs/latest/admin/actions/" rel="noopener" target="_blank">forgejo actions</a> to build this blog instead of using <em>webhooks</em>, so I looked the documentation and started playing with it until I had it working as I wanted.</p> <p>This post is to describe how I’ve installed and configured a <a href="https://forgejo.org/docs/latest/admin/runner-installation/" rel="noopener" target="_blank">forgejo runner</a>, how I’ve added an <a href="https://forgejo.mixinet.net/oci/" rel="noopener" target="_blank">oci</a> organization to my instance to build, publish and mirror container images and added a couple of additional organizations (<a href="https://forgejo.mixinet.net/actions/" rel="noopener" target="_blank">actions</a> and <a href="https://forgejo.mixinet.net/docker/" rel="noopener" target="_blank">docker</a> for now) to mirror interesting actions.</p> <p>The changes made to build the site using actions will be documented on a separate post, as I’ll be using this entry to test the new setup on the blog project.</p> <section class="doc-section level-1"><h2 id="_installing_the_runner">Installing the runner</h2><p>The first thing I’ve done is to install a runner on my server, I decided to use the <a href="https://forgejo.org/docs/latest/admin/runner-installation/#oci-image-installation">OCI image installation method</a>, as it seemed to be the easiest and fastest one.</p> <p>The commands I’ve used to setup the runner are the following:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="nv">$ </span><span class="nb">cd</span> /srv <span class="nv">$ </span>git clone https://forgejo.mixinet.net/blogops/forgejo-runner.git <span class="nv">$ </span><span class="nb">cd </span>forgejo-runner <span class="nv">$ </span>sh ./bin/setup-runner.sh</code></pre></div> <p>The <code>setup-runner.sh</code> script does multiple things:</p> <div class="ulist"><ul><li>create a <code>forgejo-runner</code> user and group</li><li>create the necessary directories for the runner</li><li>create a <code>.runner</code> file with a predefined secret and the docker label</li></ul></div> <p>The <code>setup-runner.sh</code> code is available <a href="https://forgejo.mixinet.net/blogops/forgejo-runner//src/branch/main/bin/setup-runner.sh" rel="noopener" target="_blank">here</a>.</p> <p>After running the script the runner has to be registered with the forgejo server, it can be done using the following command:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="nv">$ </span>forgejo forgejo-cli actions register <span class="nt">--name</span> <span class="s2">"</span><span class="nv">$RUNNER_NAME</span><span class="s2">"</span> <span class="se">\</span> <span class="nt">--secret</span> <span class="s2">"</span><span class="nv">$FORGEJO_SECRET</span><span class="s2">"</span></code></pre></div> <p>The <code>RUNNER_NAME</code> variable is defined on the <code>setup-runner.sh</code> script and the <code>FORGEJO_SECRET</code> must match the value used on the <code>.runner</code> file.</p> <aside class="admonition-block note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>The secret was pre-created on the <code>setup-runner.sh</code> script using <code>openssl</code>, but the runner can also be created using the forgejo server web interface; in that case the <code>setup-runner.sh</code> script would have to be modified to use the secret provided by the web interface.</p></aside></section> <section class="doc-section level-1"><h2 id="_starting_it_with_docker_compose">Starting it with <code>docker-compose</code></h2><p>To launch the runner I’m going to use a <code>docker-compose.yml</code> file that starts two containers, a <code>docker</code> in <code>docker</code> service to run the containers used by the workflow jobs and another one that runs the <code>forgejo-runner</code> itself.</p> <p>The initial version used a TCP port to communicate with the <code>dockerd</code> server from the runner, but when I tried to build images from a workflow I noticed that the containers launched by the <code>runner</code> were not going to be able to execute another <code>dockerd</code> inside the <code>dind</code> one and, even if they were, it was going to be expensive computationally.</p> <p>To avoid the issue I modified the <code>dind</code> service to use a unix socket on a shared volume that can be used by the <code>runner</code> service to communicate with the daemon and also re-shared with the job containers so the <code>dockerd</code> server can be used from them to build images.</p> <section class="admonition-block warning"><h6 class="block-title label-only"><span class="title-label">Warning: </span></h6><p>The use of the same docker server that runs the jobs from them has security implications, but this instance is for a home server where I am the only user, so I am not worried about it and this way I can save some resources (in fact, I could use the host docker server directly instead of using a <code>dind</code> service, but just in case I want to run other containers on the host I prefer to keep the one used for the runner isolated from it).</p> <p>For those concerned about sharing the same server an alternative would be to launch a second <code>dockerd</code> only for the jobs (i.e. <code>actions-dind</code>) using the same approach (the volume with its socket will have to be shared with the <code>runner</code> service so it can be re-shared, but the <code>runner</code> does not need to use it).</p></section> <p>The final <code>docker-compose.yaml</code> file is as follows:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="na">services</span><span class="pi">:</span> <span class="na">dind</span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">docker:dind</span> <span class="na">container_name</span><span class="pi">:</span> <span class="s1">'</span><span class="s">dind'</span> <span class="na">privileged</span><span class="pi">:</span> <span class="s1">'</span><span class="s">true'</span> <span class="na">command</span><span class="pi">:</span> <span class="pi">[</span><span class="s1">'</span><span class="s">dockerd'</span><span class="pi">,</span> <span class="s1">'</span><span class="s">-H'</span><span class="pi">,</span> <span class="s1">'</span><span class="s">unix:///dind/docker.sock'</span><span class="pi">,</span> <span class="s1">'</span><span class="s">-G'</span><span class="pi">,</span> <span class="s1">'</span><span class="s">$RUNNER_GID'</span><span class="pi">]</span> <span class="na">restart</span><span class="pi">:</span> <span class="s1">'</span><span class="s">unless-stopped'</span> <span class="na">volumes</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">./dind:/dind</span> <span class="na">runner</span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s1">'</span><span class="s">data.forgejo.org/forgejo/runner:6.2.2'</span> <span class="na">links</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">dind</span> <span class="na">depends_on</span><span class="pi">:</span> <span class="na">dind</span><span class="pi">:</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">service_started</span> <span class="na">container_name</span><span class="pi">:</span> <span class="s1">'</span><span class="s">runner'</span> <span class="na">environment</span><span class="pi">:</span> <span class="na">DOCKER_HOST</span><span class="pi">:</span> <span class="s1">'</span><span class="s">unix:///dind/docker.sock'</span> <span class="na">user</span><span class="pi">:</span> <span class="s">$RUNNER_UID:$RUNNER_GID</span> <span class="na">volumes</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">./config.yaml:/config.yaml</span> <span class="pi">-</span> <span class="s">./data:/data</span> <span class="pi">-</span> <span class="s">./dind:/dind</span> <span class="na">restart</span><span class="pi">:</span> <span class="s1">'</span><span class="s">unless-stopped'</span> <span class="na">command</span><span class="pi">:</span> <span class="s1">'</span><span class="s">/bin/sh</span><span class="nv"> </span><span class="s">-c</span><span class="nv"> </span><span class="s">"sleep</span><span class="nv"> </span><span class="s">5;</span><span class="nv"> </span><span class="s">forgejo-runner</span><span class="nv"> </span><span class="s">daemon</span><span class="nv"> </span><span class="s">-c</span><span class="nv"> </span><span class="s">/config.yaml"'</span></code></pre></div> <p>There are multiple things to comment about this file:</p> <div class="olist arabic"><ol class="arabic"><li>The <code>dockerd</code> server is started with the <code>-H unix:///dind/docker.sock</code> flag to use the unix socket to communicate with the daemon instead of using a TCP port (as said, it is faster and allows us to share the socket with the containers started by the runner).</li><li>We are running the <code>dockerd</code> daemon with the <code>RUNNER_GID</code> group so the runner can communicate with it (the socket gets that group which is the same used by the runner).</li><li>The runner container mounts three volumes: the <code>data</code> directory, the <code>dind</code> folder where docker creates the unix socket and a <code>config.yaml</code> file used by us to change the default runner configuration.</li></ol></div> <p>The <code>config.yaml</code> file was originally created using the <code>forgejo-runner</code>:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="nv">$ </span>docker run <span class="nt">--rm</span> data.forgejo.org/forgejo/runner:6.2.2 <span class="se">\</span> forgejo-runner generate-config <span class="o">></span> config.yaml</code></pre></div> <p>The changes to it are minimal, the runner <code>capacity</code> has been increased to <code>2</code> (that allows it to run two jobs at the same time) and the <code>/dind/docker.sock</code> value has been added to the <code>valid_volumes</code> key to allow the containers launched by the runner to mount it when needed; the diff against the default version is as follows:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="p">@@ -13,7 +13,8 @@</span> # Where to store the registration result. file: .runner # Execute how many tasks concurrently at the same time. <span class="gd">- capacity: 1 </span><span class="gi">+ # STO: Allow 2 concurrent tasks + capacity: 2 </span> # Extra environment variables to run jobs. envs: A_TEST_ENV_NAME_1: a_test_env_value_1 <span class="p">@@ -87,7 +88,9 @@</span> # If you want to allow any volume, please use the following configuration: # valid_volumes: # - '**' <span class="gd">- valid_volumes: [] </span><span class="gi">+ # STO: Allow to mount the /dind/docker.sock on the containers + valid_volumes: + - /dind/docker.sock </span> # overrides the docker client host with the specified one. # If "-" or "", an available docker host will automatically be found. # If "automount", an available docker host will automatically be found and ...</code></pre></div> <p>To start the runner we export the <code>RUNNER_UID</code> and <code>RUNNER_GID</code> variables and call <code>docker-compose up</code> to start the containers on the background:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="nv">$ RUNNER_UID</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-u</span> forgejo-runner<span class="si">)</span><span class="s2">"</span> <span class="nv">RUNNER_GID</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">id</span> <span class="nt">-g</span> forgejo-runner<span class="si">)</span><span class="s2">"</span> <span class="se">\</span> docker compose up <span class="nt">-d</span></code></pre></div> <p>If the server was configured right we are now able to start using actions with this runner.</p></section> <section class="doc-section level-1"><h2 id="_preparing_the_system_to_run_things_locally">Preparing the system to run things locally</h2><p>To avoid unnecessary network traffic we are going to create a multiple organizations in our forgejo instance to maintain our own actions and container images and mirror remote ones.</p> <p>The rationale behind the mirror use is that we reduce a lot the need to connect to remote servers to download the actions and images, which is good for performance and security reasons.</p> <p>In fact, we are going to build our own images for some things to install the tools we want without needing to do it over and over again on the workflow jobs.</p> <section class="doc-section level-2"><h3 id="_mirrored_actions">Mirrored actions</h3><p>The actions we are mirroring are on the <a href="https://forgejo.mixinet.net/actions/" rel="noopener" target="_blank">actions</a> and <a href="https://forgejo.mixinet.net/docker/" rel="noopener" target="_blank">docker</a> organizations, we have created the following ones for now (the mirrors were created using the forgejo web interface and we have disabled manually all the forgejo modules except the <code>code</code> one for them):</p> <div class="ulist"><ul><li><a href="https://forgejo.mixinet.net/actions/checkout" rel="noopener" target="_blank">actions/checkout</a>: Action for checking out a repo.</li><li><a href="https://forgejo.mixinet.net/docker/login-action" rel="noopener" target="_blank">docker/login-action</a>: Action to login against a Docker registry.</li><li><a href="https://forgejo.mixinet.net/docker/setup-buildx-action" rel="noopener" target="_blank">docker/setup-buildx-action</a>: Action to set up Docker Buildx.</li><li><a href="https://forgejo.mixinet.net/docker/build-push-action" rel="noopener" target="_blank">docker/build-push-action</a>: Action to build and push Docker images with Buildx.</li></ul></div> <p>To use our actions by default (i.e., without needing to add the server URL on the <code>uses</code> keyword) we have added the following section to the <code>app.ini</code> file of our forgejo server:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="nn">[actions]</span> <span class="py">ENABLED</span> <span class="p">=</span> <span class="s">true</span> <span class="py">DEFAULT_ACTIONS_URL</span> <span class="p">=</span> <span class="s">https://forgejo.mixinet.net</span></code></pre></div></section> <section class="doc-section level-2"><h3 id="_setting_up_credentials_to_push_images">Setting up credentials to push images</h3><p>To be able to push images to the <code>oci</code> organization I’ve created a <code>token</code> with <code>package:write</code> permission for my own user because I’m a member of the organization and I’m authorized to publish packages on it (a different user could be created, but as I said this is for personal use, so there is no need to complicate things for now).</p> <p>To allow the use of those credentials on the actions I have added a <code>secret</code> (<code>REGISTRY_PASS</code>) and a <code>variable</code> (<code>REGISTRY_USER</code>) to the <code>oci</code> organization to allow the actions to use them.</p> <p>I’ve also logged myself on my local docker client to be able to push images to the <code>oci</code> group by hand, as I it is needed for bootstrapping the system (as I’m using local images on the worflows I need to push them to the server before running the ones that are used to build the images).</p></section> <section class="doc-section level-2"><h3 id="_local_and_mirrored_images">Local and mirrored images</h3><p>Our images will be stored on the packages section of a new organization called <a href="https://forgejo.mixinet.net/oci/" rel="noopener" target="_blank">oci</a>, inside it we have created two projects that use forgejo actions to keep things in shape:</p> <div class="ulist"><ul><li><a href="https://forgejo.mixinet.net/oci/images/" rel="noopener" target="_blank">images</a>: contains the source files used to generate our own images and the actions to build, tag and push them to the <code>oci</code> organization group.</li><li><a href="https://forgejo.mixinet.net/oci/mirrors/" rel="noopener" target="_blank">mirrors</a>: contains a configuration file for the <a href="https://regclient.org/usage/regsync/" rel="noopener" target="_blank">regsync</a> tool to mirror containers and an action to run it.</li></ul></div> <p>On the next sections we are going to describe the actions and images we have created and mirrored from those projects.</p></section></section> <section class="doc-section level-1"><h2 id="_the_ociimages_project">The <code>oci/images</code> project</h2><p>The <code>images</code> project is a monorepo that contains the source files for the images we are going to build and a couple of actions.</p> <p>The image sources are on sub directories of the repository, to be considered an image the folder has to contain a <code>Dockerfile</code> that will be used to build the image.</p> <p>The repository has two workflows:</p> <div class="ulist"><ul><li><code>build-image-from-tag</code>: Workflow to build, tag and push an image to the <code>oci</code> organization</li><li><code>multi-semantic-release</code>: Workflow to create tags for the images using the <code>multi-semantic-release</code> tool.</li></ul></div> <p>As the workflows are already configured to use some of our images we pushed some of them from a checkout of the repository using the following commands:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="nv">registry</span><span class="o">=</span><span class="s2">"forgejo.mixinet.net/oci"</span> <span class="k">for </span>img <span class="k">in </span>alpine-mixinet node-mixinet multi-semantic-release<span class="p">;</span> <span class="k">do </span>docker build <span class="nt">-t</span> <span class="nv">$registry</span>/<span class="nv">$img</span>:1.0.0 <span class="nv">$img</span> docker tag <span class="nv">$registry</span>/<span class="nv">$img</span>:1.0.0 <span class="nv">$registry</span>/<span class="nv">$img</span>:latest docker push <span class="nv">$registry</span>/<span class="nv">$img</span>:1.0.0 docker push <span class="nv">$registry</span>/<span class="nv">$img</span>:latest <span class="k">done</span></code></pre></div> <p>On the next sub sections we will describe what the workflows do and will show their source code.</p> <section class="doc-section level-2"><h3 id="_build_image_from_tag_workflow"><code>build-image-from-tag</code> workflow</h3><p>This workflow uses a <code>docker</code> client to build an image from a tag on the repository with the format <code>image-name-v[0-9].[0-9].[0-9]+</code>.</p> <p>As the <code>runner</code> is executed on a <code>container</code> (instead of using <code>lxc</code>) it seemed unreasonable to run another <code>dind</code> container from that one, that is why, after some tests, I decided to share the <code>dind</code> service server socket with the <code>runner</code> container and enabled the option to mount it also on the containers launched by the runner when needed (I only do it on the <code>build-image-from-tag</code> action for now).</p> <p>The action was configured to run using a trigger or when new tags with the right format were created, but when the tag is created by <code>multi-semantic-release</code> the trigger does not work for some reason, so now it only runs the job on triggers and checks if it is launched for a tag with the right format on the job itself.</p> <p>The source code of the action is as follows:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">build-image-from-tag</span> <span class="na">on</span><span class="pi">:</span> <span class="na">workflow_dispatch</span><span class="pi">:</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">build</span><span class="pi">:</span> <span class="c1"># Don't build the image if the registry credentials are not set, the ref is not a tag or it doesn't contain '-v'</span> <span class="na">if</span><span class="pi">:</span> <span class="s">${{ vars.REGISTRY_USER != '' && secrets.REGISTRY_PASS != '' && startsWith(github.ref, 'refs/tags/') && contains(github.ref, '-v') }}</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">docker</span> <span class="na">container</span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">forgejo.mixinet.net/oci/node-mixinet:latest</span> <span class="c1"># Mount the dind socket on the container at the default location</span> <span class="na">options</span><span class="pi">:</span> <span class="s">-v /dind/docker.sock:/var/run/docker.sock</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Extract image name and tag from git and get registry name from env</span> <span class="na">id</span><span class="pi">:</span> <span class="s">job_data</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">echo "::set-output name=img_name::${GITHUB_REF_NAME%%-v*}"</span> <span class="s">echo "::set-output name=img_tag::${GITHUB_REF_NAME##*-v}"</span> <span class="s">echo "::set-output name=registry::$(</span> <span class="s">echo "${{ github.server_url }}" | sed -e 's%https://%%'</span> <span class="s">)"</span> <span class="s">echo "::set-output name=oci_registry_prefix::$(</span> <span class="s">echo "${{ github.server_url }}/oci" | sed -e 's%https://%%'</span> <span class="s">)"</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout the repo</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Export build dir and Dockerfile</span> <span class="na">id</span><span class="pi">:</span> <span class="s">build_data</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">img="${{ steps.job_data.outputs.img_name }}"</span> <span class="s">build_dir="$(pwd)/${img}"</span> <span class="s">dockerfile="${build_dir}/Dockerfile"</span> <span class="s">if [ -f "$dockerfile" ]; then</span> <span class="s">echo "::set-output name=build_dir::$build_dir"</span> <span class="s">echo "::set-output name=dockerfile::$dockerfile"</span> <span class="s">else</span> <span class="s">echo "Couldn't find the Dockerfile for the '$img' image"</span> <span class="s">exit 1</span> <span class="s">fi</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Login to the Container Registry</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">docker/login-action@v3</span> <span class="na">with</span><span class="pi">:</span> <span class="na">registry</span><span class="pi">:</span> <span class="s">${{ steps.job_data.outputs.registry }}</span> <span class="na">username</span><span class="pi">:</span> <span class="s">${{ vars.REGISTRY_USER }}</span> <span class="na">password</span><span class="pi">:</span> <span class="s">${{ secrets.REGISTRY_PASS }}</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set up Docker Buildx</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">docker/setup-buildx-action@v3</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build and Push</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">docker/build-push-action@v6</span> <span class="na">with</span><span class="pi">:</span> <span class="na">push</span><span class="pi">:</span> <span class="kc">true</span> <span class="na">tags</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">${{ steps.job_data.outputs.oci_registry_prefix }}/${{ steps.job_data.outputs.img_name }}:${{ steps.job_data.outputs.img_tag }}</span> <span class="s">${{ steps.job_data.outputs.oci_registry_prefix }}/${{ steps.job_data.outputs.img_name }}:latest</span> <span class="na">context</span><span class="pi">:</span> <span class="s">${{ steps.build_data.outputs.build_dir }}</span> <span class="na">file</span><span class="pi">:</span> <span class="s">${{ steps.build_data.outputs.dockerfile }}</span> <span class="na">build-args</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">OCI_REGISTRY_PREFIX=${{ steps.job_data.outputs.oci_registry_prefix }}/</span></code></pre></div> <p>Some notes about this code:</p> <div class="olist arabic"><ol class="arabic"><li>The <code>if</code> condition of the <code>build</code> job is not perfect, but it is good enough to avoid wrong uses as long as nobody uses manual tags with the wrong format and expects things to work (it checks if the <code>REGISTRY_USER</code> and <code>REGISTRY_PASS</code> variables are set, if the <code>ref</code> is a tag and if it contains the <code>-v</code> string).</li><li>To be able to access the <code>dind</code> socket we mount it on the container using the <code>options</code> key on the <code>container</code> section of the job (this only works if supported by the runner configuration as explained before).</li><li>We use the <code>job_data</code> step to get information about the image from the tag and the registry URL from the environment variables, it is executed first because all the information is available without checking out the repository.</li><li>We use the <code>job_data</code> step to get the build dir and <code>Dockerfile</code> paths from the repository (right now we are assuming fixed paths and checking if the <code>Dockerfile</code> exists, but in the future we could use a configuration file to get them, if needed).</li><li>As we are using a docker daemon that is already running there is no need to use the <a href="https://github.com/docker/setup-docker-action">docker/setup-docker-action</a> to install it.</li><li>On the build and push step we pass the <code>OCI_REGISTRY_PREFIX</code> build argument to the <code>Dockerfile</code> to be able to use it on the <code>FROM</code> instruction (we are using it in our images).</li></ol></div></section> <section class="doc-section level-2"><h3 id="_multi_semantic_release_workflow"><code>multi-semantic-release</code> workflow</h3><p>This workflow is used to run the <code>multi-semantic-release</code> tool on pushes to the <code>main</code> branch.</p> <p>It is configured to create the configuration files on the fly (it prepares things to tag the folders that contain a <code>Dockerfile</code> using a couple of template files available on the repository’s <code>.forgejo</code> directory) and run the <code>multi-semantic-release</code> tool to create tags and push them to the repository if new versions are to be built.</p> <p>Initially we assumed that the tag creation pushed by <code>multi-semantic-release</code> would be enough to run the <code>build-tagged-image-task</code> action, but as it didn’t work we removed the rule to run the action on tag creation and added code to trigger the action using an api call for the newly created tags (we get them from the output of the <code>multi-semantic-release</code> execution).</p> <p>The source code of the action is as follows:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">multi-semantic-release</span> <span class="na">on</span><span class="pi">:</span> <span class="na">push</span><span class="pi">:</span> <span class="na">branches</span><span class="pi">:</span> <span class="pi">-</span> <span class="s1">'</span><span class="s">main'</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">multi-semantic-release</span><span class="pi">:</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">docker</span> <span class="na">container</span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">forgejo.mixinet.net/oci/multi-semantic-release:latest</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout the repo</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Generate multi-semantic-release configuration</span> <span class="na">shell</span><span class="pi">:</span> <span class="s">sh</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s"># Get the list of images to work with (the folders that have a Dockerfile)</span> <span class="s">images="$(for img in */Dockerfile; do dirname "$img"; done)"</span> <span class="s"># Generate a values.yaml file for the main packages.json file</span> <span class="s">package_json_values_yaml=".package.json-values.yaml"</span> <span class="s">echo "images:" >"$package_json_values_yaml"</span> <span class="s">for img in $images; do</span> <span class="s">echo " - $img" >>"$package_json_values_yaml"</span> <span class="s">done</span> <span class="s">echo "::group::Generated values.yaml for the project"</span> <span class="s">cat "$package_json_values_yaml"</span> <span class="s">echo "::endgroup::"</span> <span class="s"># Generate the package.json file validating that is a good json file with jq</span> <span class="s">tmpl -f "$package_json_values_yaml" ".forgejo/package.json.tmpl" | jq . > "package.json"</span> <span class="s">echo "::group::Generated package.json for the project"</span> <span class="s">cat "package.json"</span> <span class="s">echo "::endgroup::"</span> <span class="s"># Remove the temporary values file</span> <span class="s">rm -f "$package_json_values_yaml"</span> <span class="s"># Generate the package.json file for each image</span> <span class="s">for img in $images; do</span> <span class="s">tmpl -v "img_name=$img" -v "img_path=$img" ".forgejo/ws-package.json.tmpl" | jq . > "$img/package.json"</span> <span class="s">echo "::group::Generated package.json for the '$img' image"</span> <span class="s">cat "$img/package.json"</span> <span class="s">echo "::endgroup::"</span> <span class="s">done</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Run multi-semantic-release</span> <span class="na">shell</span><span class="pi">:</span> <span class="s">sh</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">multi-semantic-release | tee .multi-semantic-release.log</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Trigger builds</span> <span class="na">shell</span><span class="pi">:</span> <span class="s">sh</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s"># Get the list of tags published on the previous steps</span> <span class="s">tags="$(</span> <span class="s">sed -n -e 's/^\[.*\] \[\(.*\)\] .* Published release \([0-9]\+\.[0-9]\+\.[0-9]\+\) on .*$/\1-v\2/p' \</span> <span class="s">.multi-semantic-release.log</span> <span class="s">)"</span> <span class="s">rm -f .multi-semantic-release.log</span> <span class="s">if [ "$tags" ]; then</span> <span class="s"># Prepare the url for building the images</span> <span class="s">workflow="build-image-from-tag.yaml"</span> <span class="s">dispatch_url="${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows/$workflow/dispatches"</span> <span class="s">echo "$tags" | while read -r tag; do</span> <span class="s">echo "Triggering build for tag '$tag'"</span> <span class="s">curl \</span> <span class="s">-H "Content-Type:application/json" \</span> <span class="s">-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \</span> <span class="s">-d "{\"ref\":\"$tag\"}" "$dispatch_url"</span> <span class="s">done</span> <span class="s">fi</span></code></pre></div> <p>Notes about this code:</p> <div class="olist arabic"><ol class="arabic"><li>The use of the <code>tmpl</code> tool to process the <code>multi-semantic-release</code> configuration templates comes from previous uses, but on this case we could use a different approach (i.e. <code>envsubst</code> could be used) but we left it because it keeps things simple and can be useful in the future if we want to do more complex things with the template files.</li><li>We use <code>tee</code> to show and dump to a file the output of the <code>multi-semantic-release</code> execution.</li><li>We get the list of pushed <code>tags</code> using <code>sed</code> against the output of the <code>multi-semantic-release</code> execution and for each one found we use <code>curl</code> to call the <code>forgejo</code> API to trigger the build job; as the call is against the same project we can use the <code>GITHUB_TOKEN</code> generated for the workflow to do it, without creating a user token that has to be shared as a secret.</li></ol></div> <p>The <code>.forgejo/package.json.tmpl</code> file is the following one:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"multi-semantic-release"</span><span class="p">,</span><span class="w"> </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0.0.0-semantically-released"</span><span class="p">,</span><span class="w"> </span><span class="nl">"private"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"> </span><span class="nl">"multi-release"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"tagFormat"</span><span class="p">:</span><span class="w"> </span><span class="s2">"${name}-v${version}"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"workspaces"</span><span class="p">:</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="err">.images</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="err">toJson</span><span class="w"> </span><span class="p">}}</span><span class="w"> </span><span class="p">}</span></code></pre></div> <p>As can be seen it only needs a list of paths to the images as argument (the file we generate contains the names and paths, but it could be simplified).</p> <p>And the <code>.forgejo/ws-package.json.tmpl</code> file is the following one:</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{{ .img_name }}"</span><span class="p">,</span><span class="w"> </span><span class="nl">"license"</span><span class="p">:</span><span class="w"> </span><span class="s2">"UNLICENSED"</span><span class="p">,</span><span class="w"> </span><span class="nl">"release"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"plugins"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"@semantic-release/commit-analyzer"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"preset"</span><span class="p">:</span><span class="w"> </span><span class="s2">"conventionalcommits"</span><span class="p">,</span><span class="w"> </span><span class="nl">"releaseRules"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"breaking"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"> </span><span class="nl">"release"</span><span class="p">:</span><span class="w"> </span><span class="s2">"major"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"revert"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"> </span><span class="nl">"release"</span><span class="p">:</span><span class="w"> </span><span class="s2">"patch"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"feat"</span><span class="p">,</span><span class="w"> </span><span class="nl">"release"</span><span class="p">:</span><span class="w"> </span><span class="s2">"minor"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fix"</span><span class="p">,</span><span class="w"> </span><span class="nl">"release"</span><span class="p">:</span><span class="w"> </span><span class="s2">"patch"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"perf"</span><span class="p">,</span><span class="w"> </span><span class="nl">"release"</span><span class="p">:</span><span class="w"> </span><span class="s2">"patch"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"semantic-release-replace-plugin"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"replacements"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"files"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"{{ .img_path }}/msr.yaml"</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^version:.*$"</span><span class="p">,</span><span class="w"> </span><span class="nl">"to"</span><span class="p">:</span><span class="w"> </span><span class="s2">"version: ${nextRelease.version}"</span><span class="p">,</span><span class="w"> </span><span class="nl">"allowEmptyPaths"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"@semantic-release/git"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"assets"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"msr.yaml"</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ci(release): {{ .img_name }}-v${nextRelease.version}</span><span class="se">\n\n</span><span class="s2">${nextRelease.notes}"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="nl">"branches"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"main"</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span></code></pre></div></section></section> <section class="doc-section level-1"><h2 id="_the_ocimirrors_project">The <code>oci/mirrors</code> project</h2><p>The repository contains a template for the configuration file we are going to use with <code>regsync</code> (<code>regsync.envsubst.yml</code>) to mirror images from remote registries using a workflow that generates a configuration file from the template and runs the tool.</p> <p>The initial version of the <code>regsync.envsubst.yml</code> file is prepared to mirror <code>alpine</code> containers from version <code>3.21</code> to <code>3.29</code> (we explicitly remove version <code>3.20</code>) and needs the <code>forgejo.mixinet.net/oci/node-mixinet:latest</code> image to run (as explained before it was pushed manually to the server):</p> <div class="listing-block"><pre class="rouge highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="m">1</span> <span class="na">creds</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">registry</span><span class="pi">:</span> <span class="s2">"</span><span class="s">$REGISTRY"</span> <span class="na">user</span><span class="pi">:</span> <span class="s2">"</span><span class="s">$REGISTRY_USER"</span> <span class="na">pass</span><span class="pi">:</span> <span class="s2">"</span><span class="s">$REGISTRY_PASS"</span> <span class="na">sync</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">source</span><span class="pi">:</span> <span class="s">alpine</span> <span class="na">target</span><span class="pi">:</span> <span class="s">$REGISTRY/oci/alpine</span> <span class="na">type</span><span class="pi">:</span> <span class="s">repository</span> <span class="na">tags</span><span class="pi">:</span> <span class="na">allow</span><span class="pi">:</span> <span class="pi">-</span> <span class="s2">"</span><span class="s">latest"</span> <span class="pi">-</span> <span class="s2">"</span><span class="s">3</span><span class="se">\\</span><span class="s">.2</span><span class="se">\\</span><span class="s">d+"</span> <span class="pi">-</span> <span class="s2">"</span><span class="s">3</span><span class="se">\\</span><span class="s">.2</span><span class="se">\\</span><span class="s">d+.</span><span class="se">\\</span><span class="s">d+"</span> <span class="na">deny</span><span class="pi">:</span> <span class="pi">-</span> <span class="s2">"</span><span class="s">3</span><span class="se">\\</span><span class="s">.20"</span> <span class="pi">-</span> <span class="s2">"</span><span class="s">3</span><span class="se">\\</span><span class="s">.20.</span><span class="se">\\</span><span class="s">d+"</span></code></pre></div> <section class="doc-section level-2"><h3 id="_mirror_workflow"><code>mirror</code> workflow</h3><p>The <code>mirror</code> workflow creates a configuration file replacing the value of the <code>REGISTRY</code> environment variable (computed by removing the protocol from the <code>server_url</code>), the <code>REGISTRY_USER</code> organization value and the <code>REGISTRY_PASS</code> secret using the <code>envsubst</code> command and running the <code>regsync</code> tool to mirror the images using the configuration file.</p> <p>The action is configured to run daily, on push events when the <code>regsync.envsubst.yml</code> file is modified on the <code>main</code> branch and can also be triggered manually.</p> <p>The source code of the action is as follows:</p> <figure class="listing-block">.forgejo/workflows/mirror.yaml <pre class="rouge highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">mirror</span> <span class="na">on</span><span class="pi">:</span> <span class="na">schedule</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s1">'</span><span class="s">@daily'</span> <span class="na">push</span><span class="pi">:</span> <span class="na">branches</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">main</span> <span class="na">paths</span><span class="pi">:</span> <span class="pi">-</span> <span class="s1">'</span><span class="s">regsync.envsubst.yml'</span> <span class="na">workflow_dispatch</span><span class="pi">:</span> <span class="na">jobs</span><span class="pi">:</span> <span class="na">mirror</span><span class="pi">:</span> <span class="na">if</span><span class="pi">:</span> <span class="s">${{ vars.REGISTRY_USER != '' && secrets.REGISTRY_PASS != '' }}</span> <span class="na">runs-on</span><span class="pi">:</span> <span class="s">docker</span> <span class="na">container</span><span class="pi">:</span> <span class="na">image</span><span class="pi">:</span> <span class="s">forgejo.mixinet.net/oci/node-mixinet:latest</span> <span class="na">steps</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Checkout</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v4</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Sync images</span> <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span> <span class="s">REGISTRY="$(echo "${{ github.server_url }}" | sed -e 's%https://%%')" \</span> <span class="s">REGISTRY_USER="${{ vars.REGISTRY_USER }}" \</span> <span class="s">REGISTRY_PASS="${{ secrets.REGISTRY_PASS }}" \</span> <span class="s">envsubst <regsync.envsubst.yml >.regsync.yml</span> <span class="s">regsync --config .regsync.yml once</span> <span class="s">rm -f .regsync.yml</span></code></pre></figure></section></section> <section class="doc-section level-1"><h2 id="_conclusion">Conclusion</h2><p>We have installed a <code>forgejo-runner</code> and configured it to run actions for our own server and things are working fine.</p> <p>This approach allows us to have a powerful CI/CD system on a modest home server, something very useful for maintaining personal projects and playing with things without needing SaaS platforms like <a href="https://github.com/" rel="noopener" target="_blank">github</a> or <a href="https://gitlab.com/" rel="noopener" target="_blank">gitlab</a>.</p></section> </div> <p class="date"> <a href="https://blogops.mixinet.net/posts/forgejo/configuring_forgejo_actions/">17 March, 2025 07:00PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="http://dirk.eddelbuettel.com/blog"> <img class="face" src="heads/dirk.png" width="65" height="90" alt="hackergotchi for Dirk Eddelbuettel" /> </a> <h2 class="planet-title"> <a href="http://dirk.eddelbuettel.com/blog" title="Thinking inside the box">Dirk Eddelbuettel</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10_hide\" onClick=\"exclude( 'http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10_show\" style=\"display:none;\" onClick=\"show( 'http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10" class="http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10"> <div class="entry"> <h3 class="entry-title"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10">RcppExamples 0.1.10: New factor Example, Other Updates</a> </h3> <div class="content"> <p>A new version 0.1.10 of the <a href="https://dirk.eddelbuettel.com/code/rcpp.examples.html">RcppExamples</a> package is now on <a href="https://cran.r-project.org">CRAN</a>, and marks the first release in five and half years.</p> <p><a href="https://dirk.eddelbuettel.com/code/rcpp.examples.html">RcppExamples</a> provides a handful of short examples detailing by concrete working examples how to set up basic R data structures in C++. It also provides a simple example for packaging with <a href="https://www.rcpp.org">Rcpp</a>. The package provides (generally fairly) simple examples, more (and generally longer) examples are at the <a href="https://gallery.rcpp.org">Rcpp Gallery</a>.</p> <p>This releases brings a bi-directorial example of <code>factor</code> conversion, updates the <code>Date</code> example, removes the explicitly stated C++ compilation standard (which <a href="https://cran.r-project.org">CRAN</a> now nags about) and brings a number of small fixes and maintenance that accrued since the last release. The NEWS extract follows:</p> <blockquote> <h4 id="changes-in-rcppexamples-version-0.1.10-2025-03-17">Changes in RcppExamples version 0.1.10 (2025-03-17)</h4> <ul> <li><p>Simplified <code>DateExample</code> by removing unused API code</p></li> <li><p>Added a new <code>FactorExample</code> with conversion to and from character vectors</p></li> <li><p>Updated and modernised continuous integrations multiple times</p></li> <li><p>Updated a few documentation links</p></li> <li><p>Updated build configuration</p></li> <li><p>Updated README.md badges and URLs</p></li> <li><p>No longer need to set a C++ compilation standard</p></li> </ul> </blockquote> <p>Courtesy of my <a href="https://dirk.eddelbuettel.com/cranberries/">CRANberries</a>, there is also a diffstat report for <a href="https://dirk.eddelbuettel.com/cranberries/2025/03/17#RcppExamples_0.1.10">this release</a>. For questions, suggestions, or issues please use the <a href="https://github.com/eddelbuettel/rcppexamples/issues">issue tracker</a> at the <a href="https://github.com/eddelbuettel/rcppexamples">GitHub repo</a>.</p> <p style="font-size: 80%; font-style: italic;"> This post by <a href="https://dirk.eddelbuettel.com">Dirk Eddelbuettel</a> originated on his <a href="https://dirk.eddelbuettel.com/blog/">Thinking inside the box</a> blog. If you like this or other open-source work I do, you can now <a href="https://github.com/sponsors/eddelbuettel">sponsor me at GitHub</a>. </p><p></p> </div> <p class="date"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/17#rcppexamples_0.1.10">17 March, 2025 04:33PM</a> </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="https://jvalleroy.fbx.one/wordpress" title="James Valleroy">James Valleroy</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://jvalleroy.fbx.one/wordpress/?p=80_hide\" onClick=\"exclude( 'https://jvalleroy.fbx.one/wordpress/?p=80' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://jvalleroy.fbx.one/wordpress/?p=80_show\" style=\"display:none;\" onClick=\"show( 'https://jvalleroy.fbx.one/wordpress/?p=80' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://jvalleroy.fbx.one/wordpress/?p=80" class="https://jvalleroy.fbx.one/wordpress/?p=80"> <div class="entry"> <h3 class="entry-title"> <a href="https://jvalleroy.fbx.one/wordpress/?p=80">What’s New for FreedomBox in Debian 13 “trixie”</a> </h3> <div class="content"> <p>FreedomBox is a Debian blend that makes it easier to run your own server. Approximately every two years, there is a new stable release of Debian. This year’s release will be called Debian 13 "trixie".</p> <p>This post will provide an overview of changes between FreedomBox 23.6 (the version that shipped in Debian 12 "bookworm") and 25.5 (the latest release). <em>Note</em>: Debian 13 "trixie" is not yet released, so things may still change, be added or removed, before the official release.</p> <h2>General</h2> <ul> <li>A number of translations were updated, including Albanian, Arabic, Belarusian, Bulgarian, Chinese (Simplified Han script), Chinese (Traditional Han script), Czech, Dutch, French, German, Hindi, Japanese, Norwegian Bokmål, Polish, Portuguese, Russian, Spanish, Swedish, Telugu, Turkish, and Ukrainian.</li> <li>Fix cases where a package or service is used by multiple apps, so that disabling or uninstalling one app does not affect the other app.</li> <li>When uninstalling an app, purge the packages, to remove all data and configuration.</li> <li>For configuration files that need to be placed into folders owned by other packages, we now install these files under /usr/share/freedombox/etc/, and create a symbolic link to the other package’s configuration folder. This prevents the files being lost when other packages are purged.</li> <li>Add an action to re-run the setup process for an app. This can fix many of the possible issues that occur.</li> <li>Various improvements related to the "force upgrade" feature, which handles upgrading packages with conffile prompts.</li> <li>Fix install/uninstall issues for apps that use MySQL database (WordPress, Zoph).</li> <li>Improve handling of file uploads (Backups, Feather Wiki, Kiwix).</li> <li>Switch to Bootstrap 5 front-end framework.</li> <li>Removed I2P app, since the i2p package was removed from Debian.</li> <li>Various user interface changes, including: <ul> <li>Add tags for apps, replacing short descriptions. When a tag is clicked, search and filter for one or multiple tags.</li> <li>Organize the System page into sections.</li> <li>Add breadcrumbs for page hierarchy navigation.</li> <li>Add next steps page after initial FreedomBox setup.</li> </ul> </li> </ul> <h3>Diagnostics</h3> <ul> <li>Add diagnostic checks to detect common errors.</li> <li>Add diagnostics daily run, with notifications about failures.</li> <li>Add Repair action for failed diagnostics, and option for automatic repairs.</li> </ul> <h3>Name Services</h3> <ul> <li>Move hostname and domain name configuration to Names page.</li> <li>Support multiple static and/or dynamic domains.</li> <li>Use systemd-resolved for DNS resolution.</li> <li>Add options for setting global DNS-over-TLS and DNSSEC preferences.</li> </ul> <h3>Networks</h3> <ul> <li>Add more options for IPv6 configuration method.</li> <li>Overhaul Wi-Fi networks scan page.</li> </ul> <h3>Privacy</h3> <ul> <li>Add option to disable fallback DNS servers.</li> <li>Add option to set the lookup URL to get the public IP address of the FreedomBox.</li> </ul> <h3>Users and Groups</h3> <ul> <li>Delete or move home folder when user is deleted or renamed.</li> <li>When a user is inactivated, also inactivate the user in LDAP.</li> </ul> <h2>Deluge</h2> <ul> <li>This BitTorrent client app should be available once again in Debian 13 "trixie".</li> </ul> <h2>Ejabberd</h2> <ul> <li>Turn on Message Archive Management setting by default, to help various XMPP clients use it.</li> </ul> <h2>Feather Wiki</h2> <ul> <li>Add new app for note taking.</li> <li>This app lives in a single HTML file, which is downloaded from the FreedomBox website.</li> </ul> <h2>GitWeb</h2> <ul> <li>Disable snapshot feature, due to high resource use.</li> <li>Various fixes for repository operations.</li> </ul> <h2>GNOME</h2> <ul> <li>Add new app to provide a graphical desktop environment.</li> <li>Requires a monitor, keyboard, and mouse to be physically connected to the FreedomBox.</li> <li>Not suitable for low-end hardware.</li> </ul> <h2>ikiwiki</h2> <ul> <li>Disable discussion pages by default for new wiki/blog, to avoid spam.</li> </ul> <h2>Kiwix</h2> <ul> <li>Add new app for offline reader of Wikipedia and other sites.</li> </ul> <h2>Matrix Synapse</h2> <ul> <li>Add an option for token-based registration verification, so that users signing up for new accounts will need to provide a token during account registration.</li> </ul> <h2>MediaWiki</h2> <ul> <li>Allow setting the site language code.</li> <li>Increase PHP maximum execution time to 100 seconds.</li> </ul> <h2>MiniDLNA</h2> <ul> <li>Add media directory selection form.</li> </ul> <h2>Miniflux</h2> <ul> <li>Add new app for reading news from RSS/ATOM feeds.</li> </ul> <h2>Nextcloud</h2> <ul> <li>Add new app for file sync and collaboration.</li> <li>Uses a Docker container maintained by the Nextcloud community. The container is downloaded from FreedomBox container registry.</li> </ul> <h2>OpenVPN</h2> <ul> <li>Renew server/client certificates, and set expiry to 10 years.</li> </ul> <h2>Postfix/Dovecot</h2> <ul> <li>Fix DKIM signing.</li> <li>Show DNS entries for all domains.</li> </ul> <h2>Shadowsocks Server</h2> <ul> <li>Add new app for censorship resistance, separate from Shadowsocks Client app.</li> </ul> <h2>SOGo</h2> <ul> <li>Add new app for groupware (webmail, calendar, tasks, and contacts).</li> <li>Works with Postfix/Dovecot email server app.</li> </ul> <h2>TiddlyWiki</h2> <ul> <li>Add new app for note taking.</li> <li>This app lives in a single HTML file, which is downloaded from the FreedomBox website.</li> </ul> <h2>Tor Proxy</h2> <ul> <li>Add new app for Tor SOCKS proxy, separate from Tor app.</li> </ul> <h2>Transmission</h2> <ul> <li>Allow remote user interfaces to connect.</li> </ul> <h1>Conclusion</h1> <p>Over the past two years, FreedomBox has been increasing the number of features and applications available to its users. We have also focused on improving the reliability of the system, detecting unexpected situations, and providing means to return to a known good state. With these improvements, FreedomBox has become a good solution for people with limited time or energy to set up and start running a personal server, at home or in the cloud.</p> <p>Looking forward, we would like to focus on making more powerful hardware available with FreedomBox pre-installed and ready to be used. This hardware would also support larger storage devices, making it suitable as a NAS or media server. We are also very interested in exploring new features such as atomic updates, which will further enhance the reliability of the system.</p> </div> <p class="date"> <a href="https://jvalleroy.fbx.one/wordpress/?p=80">17 March, 2025 12:40PM</a> by James Valleroy </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="https://vincent.bernat.ch/en" title="Vincent Bernat">Vincent Bernat</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys_hide\" onClick=\"exclude( 'https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys_show\" style=\"display:none;\" onClick=\"show( 'https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys" class="https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys"> <div class="entry"> <h3 class="entry-title"> <a href="https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys">Offline PKI using 3 YubiKeys and an ARM single board computer</a> </h3> <div class="content"> <p>An offline <abbr title="Public Key Infrastructure">PKI</abbr> enhances security by physically isolating the certificate authority from network threats. A <a href="https://www.yubico.com/products/yubikey-5-overview/" title="Discover YubiKey 5">YubiKey</a> is a low-cost solution to store a root certificate. You also need an air-gapped environment to operate the root <abbr title="Certificate Authority">CA</abbr>.</p> <figure><div class="lf-media-outer"><span class="lf-media-inner"><img alt="PKI relying on a set of 3 YubiKeys: 2 for the root CA and 1 for the intermediate CA." class="lf-media lf-opaque" height="346" src="https://d2pzklc15kok91.cloudfront.net/images/3-yubikeys@1x.703a8bbdfe6815.jpg" width="400" /></span></div>Offline PKI backed up by 3 YubiKeys</figure> <p>This post describes an offline <abbr title="Public Key Infrastructure">PKI</abbr> system using the following components:</p> <ul> <li>2 YubiKeys for the <strong>root <abbr title="Certificate Authority">CA</abbr></strong> (with a 20-year validity),</li> <li>1 YubiKey for the <strong>intermediate <abbr title="Certificate Authority">CA</abbr></strong> (with a 5-year validity), and</li> <li>1 <a href="https://libre.computer/products/aml-s905x-cc-v2/" title="Sweet Potato AML-S905X-CC-V2">Libre Computer Sweet Potato</a> as an <strong>air-gapped <abbr title="Single Board Computer">SBC</abbr></strong>.</li> </ul> <p>It is possible to add more YubiKeys as a backup of the root <abbr title="Certificate Authority">CA</abbr> if needed. This is not needed for the intermediate <abbr title="Certificate Authority">CA</abbr> as you can generate a new one if the current one gets destroyed.</p> <h1 id="the-software-part">The software part</h1> <p><a href="https://github.com/vincentbernat/offline-pki" title="Offline PKI system"><code>offline-pki</code></a> is a small Python application to manage an offline <abbr title="Public Key Infrastructure">PKI</abbr>. It relies on <a href="https://github.com/Yubico/yubikey-manager" title="Python library for configuring any YubiKey">yubikey-manager</a> to manage YubiKeys and <a href="https://cryptography.io/en/latest/" title="cryptography's documentation">cryptography</a> for cryptographic operations not executed on the YubiKeys. The application has some opinionated design choices. Notably, the cryptography is hard-coded to use <a href="https://en.wikipedia.org/wiki/P-384" title="P-384 on Wikipedia">NIST P-384 elliptic curve</a>.</p> <p>The first step is to reset all your YubiKeys:</p> <div class="language-bash-session codehilite"><pre><span></span><span class="gp">$ </span>offline-pki<span class="w"> </span>yubikey<span class="w"> </span>reset <span class="go">This will reset the connected YubiKey. Are you sure? [y/N]: y</span> <span class="go">New PIN code:</span> <span class="go">Repeat for confirmation:</span> <span class="go">New PUK code:</span> <span class="go">Repeat for confirmation:</span> <span class="go">New management key ('.' to generate a random one):</span> <span class="go">WARNING[pki-yubikey] Using random management key: e8ffdce07a4e3bd5c0d803aa3948a9c36cfb86ed5a2d5cf533e97b088ae9e629</span> <span class="go">INFO[pki-yubikey] 0: Yubico YubiKey OTP+FIDO+CCID 00 00</span> <span class="go">INFO[pki-yubikey] SN: 23854514</span> <span class="go">INFO[yubikit.management] Device config written</span> <span class="go">INFO[yubikit.piv] PIV application data reset performed</span> <span class="go">INFO[yubikit.piv] Management key set</span> <span class="go">INFO[yubikit.piv] New PUK set</span> <span class="go">INFO[yubikit.piv] New PIN set</span> <span class="go">INFO[pki-yubikey] YubiKey reset successful!</span> </pre></div> <p>Then, generate the root <abbr title="Certificate Authority">CA</abbr> and create as many copies as you want:</p> <div class="language-bash-session codehilite"><pre><span></span><span class="gp">$ </span>offline-pki<span class="w"> </span>certificate<span class="w"> </span>root<span class="w"> </span>--permitted<span class="w"> </span>example.com <span class="go">Management key for Root X:</span> <span class="go">Plug YubiKey "Root X"...</span> <span class="go">INFO[pki-yubikey] 0: Yubico YubiKey CCID 00 00</span> <span class="go">INFO[pki-yubikey] SN: 23854514</span> <span class="go">INFO[yubikit.piv] Data written to object slot 0x5fc10a</span> <span class="go">INFO[yubikit.piv] Certificate written to slot 9C (SIGNATURE), compression=True</span> <span class="go">INFO[yubikit.piv] Private key imported in slot 9C (SIGNATURE) of type ECCP384</span> <span class="go">Copy root certificate to another YubiKey? [y/N]: y</span> <span class="go">Plug YubiKey "Root X"...</span> <span class="go">INFO[pki-yubikey] 0: Yubico YubiKey CCID 00 00</span> <span class="go">INFO[pki-yubikey] SN: 23854514</span> <span class="go">INFO[yubikit.piv] Data written to object slot 0x5fc10a</span> <span class="go">INFO[yubikit.piv] Certificate written to slot 9C (SIGNATURE), compression=True</span> <span class="go">INFO[yubikit.piv] Private key imported in slot 9C (SIGNATURE) of type ECCP384</span> <span class="go">Copy root certificate to another YubiKey? [y/N]: n</span> </pre></div> <p>You can inspect the result:</p> <div class="language-bash-session codehilite"><pre><span></span><span class="gp">$ </span>offline-pki<span class="w"> </span>yubikey<span class="w"> </span>info <span class="go">INFO[pki-yubikey] 0: Yubico YubiKey CCID 00 00</span> <span class="go">INFO[pki-yubikey] SN: 23854514</span> <span class="go">INFO[pki-yubikey] Slot 9C (SIGNATURE):</span> <span class="go">INFO[pki-yubikey] Private key type: ECCP384</span> <span class="go">INFO[pki-yubikey] Public key:</span> <span class="go">INFO[pki-yubikey] Algorithm: secp384r1</span> <span class="go">INFO[pki-yubikey] Issuer: CN=Root CA</span> <span class="go">INFO[pki-yubikey] Subject: CN=Root CA</span> <span class="go">INFO[pki-yubikey] Serial: 1</span> <span class="go">INFO[pki-yubikey] Not before: 2024-07-05T18:17:19+00:00</span> <span class="go">INFO[pki-yubikey] Not after: 2044-06-30T18:17:19+00:00</span> <span class="go">INFO[pki-yubikey] PEM:</span> <span class="go">-----BEGIN CERTIFICATE-----</span> <span class="go">MIIBcjCB+aADAgECAgEBMAoGCCqGSM49BAMDMBIxEDAOBgNVBAMMB1Jvb3QgQ0Ew</span> <span class="go">HhcNMjQwNzA1MTgxNzE5WhcNNDQwNjMwMTgxNzE5WjASMRAwDgYDVQQDDAdSb290</span> <span class="go">IENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAERg3Vir6cpEtB8Vgo5cAyBTkku/4w</span> <span class="go">kXvhWlYZysz7+YzTcxIInZV6mpw61o8W+XbxZV6H6+3YHsr/IeigkK04/HJPi6+i</span> <span class="go">zU5WJHeBJMqjj2No54Nsx6ep4OtNBMa/7T9foyMwITAPBgNVHRMBAf8EBTADAQH/</span> <span class="go">MA4GA1UdDwEB/wQEAwIBhjAKBggqhkjOPQQDAwNoADBlAjEAwYKy/L8leJyiZSnn</span> <span class="go">xrY8xv8wkB9HL2TEAI6fC7gNc2bsISKFwMkyAwg+mKFKN2w7AjBRCtZKg4DZ2iUo</span> <span class="go">6c0BTXC9a3/28V5aydZj6rvx0JqbF/Ln5+RQL6wFMLoPIvCIiCU=</span> <span class="go">-----END CERTIFICATE-----</span> </pre></div> <p>Then, you can create an intermediate certificate with <code>offline-pki yubikey intermediate</code> and use it to sign certificates by providing a <abbr title="Certificate Signing Request">CSR</abbr> to <code>offline-pki certificate sign</code>. Be careful and inspect the <abbr title="Certificate Signing Request">CSR</abbr> before signing it, as only the subject name can be overridden. Check the <a href="https://github.com/vincentbernat/offline-pki?tab=readme-ov-file#operations">documentation</a> for more details. Get the available options using the <code>--help</code> flag.</p> <h1 id="the-hardware-part">The hardware part</h1> <p>To ensure the operations on the root and intermediate <abbr title="Certificate Authorities">CAs</abbr> are air-gapped, a cost-efficient solution is to use an ARM64 single board computer. The <a href="https://libre.computer/products/aml-s905x-cc-v2/" title="Sweet Potato AML-S905X-CC-V2">Libre Computer Sweet Potato</a> <abbr title="Single Board Computer">SBC</abbr> is a more open alternative to the well-known Raspberry Pi.<sup id="fnref-root"><a class="footnote-ref" href="https://vincent.bernat.ch#fn-root">1</a></sup></p> <figure><div class="lf-media-outer"><span class="lf-media-inner"><img alt="Libre Computer Sweet Potato single board computer relying on the Amlogic S905X SOC" class="lf-media lf-opaque" height="560" src="https://d2pzklc15kok91.cloudfront.net/images/sweet-potato@1x.a5e31f42d65aa8.jpg" width="800" /></span></div>Libre Computer Sweet Potato SBC, powered by the AML-S905X SOC</figure> <p>I interact with it through an <a href="https://www.amazon.com/dp/B07WX2DSVB" title="USB to TTL UART converter on Amazon">USB to TTL UART converter</a>:</p> <div class="language-bash-session codehilite"><pre><span></span><span class="gp">$ </span>tio<span class="w"> </span>/dev/ttyUSB0 <span class="go">[16:40:44.546] tio v3.7</span> <span class="go">[16:40:44.546] Press ctrl-t q to quit</span> <span class="go">[16:40:44.555] Connected to /dev/ttyUSB0</span> <span class="go">GXL:BL1:9ac50e:bb16dc;FEAT:ADFC318C:0;POC:1;RCY:0;SPI:0;0.0;CHK:0;</span> <span class="go">TE: 36574</span> <span class="go">BL2 Built : 15:21:18, Aug 28 2019. gxl g1bf2b53 - luan.yuan@droid15-sz</span> <span class="go">set vcck to 1120 mv</span> <span class="go">set vddee to 1000 mv</span> <span class="go">Board ID = 4</span> <span class="go">CPU clk: 1200MHz</span> <span class="go">[…]</span> </pre></div> <h1 id="the-nix-glue">The Nix glue</h1> <p>To bring everything together, I am using <em>Nix</em> with a <a href="https://github.com/vincentbernat/offline-pki/blob/main/flake.nix">Flake</a> providing:</p> <ul> <li>a package for the <code>offline-pki</code> application, with shell completion,</li> <li>a development shell, including an editable version of the <code>offline-pki</code> application,</li> <li>a NixOS module to setup the offline <abbr title="Public Key Infrastructure">PKI</abbr>, resetting the system at each boot,</li> <li>a QEMU image for testing, and</li> <li>an SD card image to be used on the <em>Sweet Potato</em> or another ARM64 <abbr title="Single Board Computer">SBC</abbr>.</li> </ul> <div class="language-bash codehilite"><pre><span></span><span class="c1"># Execute the application locally</span> nix<span class="w"> </span>run<span class="w"> </span>github:vincentbernat/offline-pki<span class="w"> </span>--<span class="w"> </span>--help <span class="c1"># Run the application inside a QEMU VM</span> nix<span class="w"> </span>run<span class="w"> </span>github:vincentbernat/offline-pki<span class="se">\#</span>qemu <span class="c1"># Build a SD card for the Sweet Potato or for the Raspberry Pi</span> nix<span class="w"> </span>build<span class="w"> </span>--system<span class="w"> </span>aarch64-linux<span class="w"> </span>github:vincentbernat/offline-pki<span class="se">\#</span>sdcard.potato nix<span class="w"> </span>build<span class="w"> </span>--system<span class="w"> </span>aarch64-linux<span class="w"> </span>github:vincentbernat/offline-pki<span class="se">\#</span>sdcard.generic <span class="c1"># Get a development shell with the application</span> nix<span class="w"> </span>develop<span class="w"> </span>github:vincentbernat/offline-pki </pre></div> <div class="footnote"> <hr /> <ol> <li id="fn-root"> <p>The key for the root <abbr title="Certificate Authority">CA</abbr> is not generated by the YubiKey. Using an air-gapped computer is all the more important. Put it in a safe with the YubiKeys when done! <a class="footnote-backref" href="https://vincent.bernat.ch#fnref-root" title="Jump back to footnote 1 in the text">↩︎</a></p> </li> </ol> </div> </div> <p class="date"> <a href="https://vincent.bernat.ch/en/blog/2025-offline-pki-yubikeys">17 March, 2025 08:12AM</a> by Vincent Bernat </p> </div> </div> </div> <h1>March 16, 2025</h1> <div class="channel"> <h2 class="planet-title"> <a href="https://etbe.coker.com.au" title="etbe – Russell Coker">Russell Coker</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/_hide\" onClick=\"exclude( 'https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/_show\" style=\"display:none;\" onClick=\"show( 'https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/" class="https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/"> <div class="entry"> <h3 class="entry-title"> <a href="https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/">Article Recommendations via FOSS</a> </h3> <div class="content"> <p>Google tracking everything we read is bad, particularly since Google abandoned the “don’t be evil” plan and are presumably open to being somewhat evil.</p> <p>The article recommendations on Chrome on Android are useful and I’d like to be able to get the same quality of recommendations without Google knowing about everything I read. Ideally without anything other than the device I use knowing what interests me.</p> <p>A ML system to map between sources of news that are of interest should be easy to develop and run on end user devices. The model could be published and when given inputs of articles you like give an output of sites that contain other articles you like. Then an agent on the end user system could spider the sites in question and run a local model to determine which articles to present to the user.</p> <p>Mapping for hate following is possible for such a system (Google doesn’t do that), the user could have 2 separate model runs for regular reading and hate-following and determine how much of each content to recommend. It could also give negative weight to entries that match the hate criteria.</p> <p>Some sites with articles (like Medium) give an estimate of reading time. An article recommendation system should have a fixed limit of articles (both in articles and in reading time) to support the “I spend half an hour reading during lunch” model not doom scrolling.</p> <p>For getting news using only FOSS it seems that the best option at the moment is to use the <a href="https://en.wikipedia.org/wiki/Lemmy_(social_network)">Lemmy FOSS social network which is like Reddit [1]</a> to recommend articles etc.</p> <p>The <a href="https://github.com/lemmygtk/lemoa">Lemoa client for Lemmy uses GTK [2]</a> but it’s no longer maintained. The <a href="https://github.com/theycallhermax/lemonade">Lemonade client for Lemmy is written in Rust [3]</a>. It would be good if one of those was packaged for Debian, preferably one that’s maintained.</p> <ul> <li>[1]<a href="https://en.wikipedia.org/wiki/Lemmy_(social_network)"> https://en.wikipedia.org/wiki/Lemmy_(social_network)</a></li> <li>[2]<a href="https://github.com/lemmygtk/lemoa"> https://github.com/lemmygtk/lemoa</a></li> <li>[3]<a href="https://github.com/theycallhermax/lemonade"> https://github.com/theycallhermax/lemonade</a></li> </ul> <div class="yarpp yarpp-related yarpp-related-rss yarpp-template-list"> <p>Related posts:</p><ol> <li><a href="https://etbe.coker.com.au/2009/04/11/ap-copyright-web/" rel="bookmark" title="The AP and Copyright on the Web">The AP and Copyright on the Web</a> <small>The New York Times has an article about the Associated...</small></li> <li><a href="https://etbe.coker.com.au/2014/07/22/public-lectures-about-foss/" rel="bookmark" title="Public Lectures About FOSS">Public Lectures About FOSS</a> <small>Eventbrite I’ve recently started using the Eventbrite Web site [1]...</small></li> <li><a href="https://etbe.coker.com.au/2025/03/06/8k-video-cards/" rel="bookmark" title="8k Video Cards">8k Video Cards</a> <small>I previously blogged about getting an 8K TV [1]. Now...</small></li> </ol> </div> </div> <p class="date"> <a href="https://etbe.coker.com.au/2025/03/16/article-recommendations-foss/">16 March, 2025 04:19AM</a> by etbe </p> </div> </div> </div> <h1>March 15, 2025</h1> <div class="channel"> <a href="https://bits.debian.org/"> <img class="face" src="heads/dwn.png" width="77" height="85" alt="hackergotchi for Bits from Debian" /> </a> <h2 class="planet-title"> <a href="https://bits.debian.org/" title="Bits from Debian">Bits from Debian</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://bits.debian.org/2025/03/debian-med-sprint-2025.html_hide\" onClick=\"exclude( 'https://bits.debian.org/2025/03/debian-med-sprint-2025.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://bits.debian.org/2025/03/debian-med-sprint-2025.html_show\" style=\"display:none;\" onClick=\"show( 'https://bits.debian.org/2025/03/debian-med-sprint-2025.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://bits.debian.org/2025/03/debian-med-sprint-2025.html" class="https://bits.debian.org/2025/03/debian-med-sprint-2025.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://bits.debian.org/2025/03/debian-med-sprint-2025.html">Debian Med Sprint in Berlin</a> </h3> <div class="content"> <p>Debian Med sprint in Berlin on 15 and 16 February</p> <p>The Debian Med team works on software packages that are associated with medicine, pre-clinical research, and life sciences, and makes them available for the Debian distribution. Seven Debian developers and contributors to the team gathered for their annual Sprint, in Berlin, Germany on 15 and 16 February 2025. The purpose of the meeting was to tackle bugs in Debian-Med packages, enhance the quality of the team's packages, and coordinate the efforts of team members overall.</p> <p>This sprint allowed participants to fix dozens of bugs, including release-critical ones. New upstream versions were uploaded, and the participants took some time to modernize some packages. Additionally, they discussed the long-term goals of the team, prepared a forthcoming invited talk for a conference, and enjoyed working together.</p> <p>More details on the event and individual agendas/reports can be found at <a href="https://wiki.debian.org/Sprints/2025/DebianMed">https://wiki.debian.org/Sprints/2025/DebianMed</a>.</p> </div> <p class="date"> <a href="https://bits.debian.org/2025/03/debian-med-sprint-2025.html">15 March, 2025 11:00PM</a> by Pierre Gruet, Jean-Pierre Giraud, Joost van Baal-Ilić </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="https://www.scarlettgatelymoore.dev" title="Open Source Software – Scarlett Gately Moore">Scarlett Gately Moore</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/_hide\" onClick=\"exclude( 'https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/_show\" style=\"display:none;\" onClick=\"show( 'https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/" class="https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/"> <div class="entry"> <h3 class="entry-title"> <a href="https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/">KDE snaps fixed, Thank you for your support</a> </h3> <div class="content"> <div class="wp-block-image"> <figure class="aligncenter size-full"><img alt="KDE Mascot" class="wp-image-232" height="500" src="https://www.scarlettgatelymoore.dev/wp-content/uploads/300px-Mascot_20140702_konqui-group.png" width="300" />KDE Mascot</figure></div> <p>Thank you everyone for keeping the lights on for a bit longer. KDE snaps have been restored. I also released 24.12.3! In addition, I have moved “most” snaps to core24. The remaining snaps need newer qt6/kf6, which is a WIP. “The Bad luck girl” has been hit once again with another loss, so with that, I will be reducing my hours on snaps while I consider my options for my future. I am still around, just a bit less. </p> <p>Thanks again everyone, if you can get me through one more ( lingering broken arm ) surgery I would be forever grateful! <a href="https://gofund.me/d5d59582">https://gofund.me/d5d59582</a></p> </div> <p class="date"> <a href="https://www.scarlettgatelymoore.dev/kde-snaps-fixed-thank-you-for-your-support/">15 March, 2025 12:52PM</a> by sgmoore </p> </div> </div> </div> <h1>March 14, 2025</h1> <div class="channel"> <h2 class="planet-title"> <a href="https://ravidwivedi.in/posts/" title="Posts on Ravi's Blog">Ravi Dwivedi</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://ravidwivedi.in/posts/libreoffice-conference-2024/_hide\" onClick=\"exclude( 'https://ravidwivedi.in/posts/libreoffice-conference-2024/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://ravidwivedi.in/posts/libreoffice-conference-2024/_show\" style=\"display:none;\" onClick=\"show( 'https://ravidwivedi.in/posts/libreoffice-conference-2024/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://ravidwivedi.in/posts/libreoffice-conference-2024/" class="https://ravidwivedi.in/posts/libreoffice-conference-2024/"> <div class="entry"> <h3 class="entry-title"> <a href="https://ravidwivedi.in/posts/libreoffice-conference-2024/">Libreoffice Conference 2024 in Luxembourg</a> </h3> <div class="content"> <p>Last year, I attended the annual <a href="https://conference.libreoffice.org/2024/">LibreOffice Conference in Luxembourg</a> with the help of a generous travel grant by The Document Foundation (TDF). It was a three-day event from the 10th to the 12th of October 2024, with an additional day for community meetup on the 9th.</p> <p>Luxembourg is a small (twice as big as Delhi) country in Western Europe. After going through an <a href="https://ravidwivedi.in/posts/luxembourg-visa-process/">arduous visa process</a>, I reached Luxembourg on the 8th of October. Upon arriving in Luxembourg, I took a bus to the city center, where my hotel — Park Inn — was located. All the public transport in Luxembourg was free of cost. It was as if I stepped in another world. There were separate tracks for cycling and a separate lane for buses, along with good pedestrian infrastructure. In addition, the streets were pretty neat and clean.</p> <figure><img src="https://ravidwivedi.in/images/luxembourg/luxembourg-airport.jpg" width="700" /> <h4>Luxembourg's Findel Airport</h4> </figure> <figure><img src="https://ravidwivedi.in/images/luxembourg/cycling-tracks.jpg" width="700" /> <h4>Separate cycling tracks in Luxembourg</h4> </figure> <p>My hotel was 20 km from the conference venue in Belval. However, the commute was convenient due to a free of cost train connection, which were comfortable, smooth, and scenic, covering the distance in half an hour. The hotel included a breakfast buffet, recharging us before the conference.</p> <figure><img src="https://ravidwivedi.in/images/luxembourg/train.jpg" width="700" /> <h4>This is what trains look like in Luxembourg</h4> </figure> <p>Pre-conference, a day was reserved for the community meetup on the 9th of October. On that day, the community members introduced themselves and their contributions to the LibreOffice project. It acted as a brainstorming session. I got a lovely conference bag, which contained a T-Shirt, a pen and a few stickers. I also met my long time collaborators Mike, Sophie and Italo from the TDF, whom I had interacted only remotely till then. Likewise, I also met TDF’s sysadmin Guilhem, who I interacted before regarding setting up my LibreOffice mirror.</p> <figure><img src="https://ravidwivedi.in/images/luxembourg/conference-bag.jpg" width="500" /> <h4>Conference bag</h4> </figure> <p>The conference started on the 10th. There were 5 attendees from India, including me, while most of the attendees were from Europe. The talks were in English. One of the talks that stood out for me was about Luxchat — a chat service run by the Luxembourg government based on the Matrix protocol for the citizens of Luxembourg. I also liked Italo’s talk on why document formats must be freedom-respecting. On the first night, the conference took us to a nice dinner in a restaurant. It offered one more way to socialize with other attendees and explore food at the same time.</p> <figure><img src="https://ravidwivedi.in/images/luxembourg/italo-slide.jpg" width="700" /> <h4>One of the slides of Italo's talk</h4> </figure> <figure><img src="https://ravidwivedi.in/images/luxembourg/auditorium.jpg" width="700" /> <h4>Picture of the hall in which talks were held</h4> </figure> <p>On the 11th of October, I went for a walk in the morning with Biswadeep for some sightseeing around our hotel area. As a consequence, I missed the group photo of the conference, which I wanted to be in. Anyway, we enjoyed roaming around the picturesque Luxembourg city. We also sampled a tram ride to return to our hotel.</p> <figure><img src="https://ravidwivedi.in/images/luxembourg/a-view-of-luxembourg.jpg" width="700" /> <h4>We encountered such scenic views during our walk</h4> </figure> <figure><img src="https://ravidwivedi.in/images/luxembourg/view-in-luxembourg.jpg" width="700" /> <h4>Another view of Luxembourg city area</h4> </figure> <p>The conference ended on the 12th with a couple of talks. This conference gave me an opportunity to meet the global LibreOffice community, connect and share ideas. It also gave me a peek into the country of Luxembourg and its people, where I had good experience. English was widely known, and I had no issues getting by.</p> <p>Thanks to all the organizers and sponsors of the conference!</p> </div> <p class="date"> <a href="https://ravidwivedi.in/posts/libreoffice-conference-2024/">14 March, 2025 04:18PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="http://notes.secretsauce.net" title="Dima Kogan">Dima Kogan</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html_hide\" onClick=\"exclude( 'http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html_show\" style=\"display:none;\" onClick=\"show( 'http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html" class="http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html"> <div class="entry"> <h3 class="entry-title"> <a href="http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html">Getting precise timings out of RS-232 output</a> </h3> <div class="content"> <p> For uninteresting reasons I need very regular 58Hz pulses coming out of an RS-232 Tx line: the time between each pulse should be as close to 1/58s as possible. I produce each pulse by writing an <code>\xFF</code> byte to the device. The start bit is the only active-voltage bit being sent, and that produces my pulse. I wrote this obvious C program: </p> <div class="org-src-container"> <pre class="src src-c"><span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><stdio.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><stdlib.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><stdbool.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><sys/ioctl.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><unistd.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><fcntl.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><termios.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><stdint.h></span> <span style="color: #0000ee; font-weight: bold;">#include</span> <span style="color: #00cd00;"><sys/time.h></span> <span style="color: #00cdcd; font-weight: bold;">static</span> <span style="color: #00cd00;">uint64_t</span> <span style="color: #0000ee; font-weight: bold;">gettimeofday_uint64</span>() { <span style="color: #00cdcd; font-weight: bold;">struct</span> <span style="color: #00cd00;">timeval</span> <span style="color: #cdcd00;">tv</span>; gettimeofday(&tv, <span style="color: #cd00cd;">NULL</span>); <span style="color: #00cdcd; font-weight: bold;">return</span> (<span style="color: #00cd00;">uint64_t</span>) tv.tv_sec * 1000000ULL + (<span style="color: #00cd00;">uint64_t</span>) tv.tv_usec; } <span style="color: #00cd00;">int</span> <span style="color: #0000ee; font-weight: bold;">main</span>(<span style="color: #00cd00;">int</span> <span style="color: #cdcd00;">argc</span>, <span style="color: #00cd00;">char</span>* <span style="color: #cdcd00;">argv</span>[]) { <span style="color: #cdcd00;">// </span><span style="color: #cdcd00;">open the serial device, and make it as raw as possible</span> <span style="color: #00cdcd; font-weight: bold;">const</span> <span style="color: #00cd00;">char</span>* <span style="color: #cdcd00;">device</span> = <span style="color: #00cd00;">"/dev/ttyS0"</span>; <span style="color: #00cdcd; font-weight: bold;">const</span> <span style="color: #00cd00;">speed_t</span> <span style="color: #cdcd00;">baud</span> = B9600; <span style="color: #00cd00;">int</span> <span style="color: #cdcd00;">fd</span> = open(device, O_WRONLY|O_NOCTTY); tcflush(fd, TCIOFLUSH); <span style="color: #00cdcd; font-weight: bold;">struct</span> <span style="color: #00cd00;">termios</span> <span style="color: #cdcd00;">options</span> = {.c_iflag = IGNBRK, .c_cflag = CS8 | CREAD | CLOCAL}; cfsetspeed(&options, baud); tcsetattr(fd, TCSANOW, &options); <span style="color: #00cdcd; font-weight: bold;">const</span> <span style="color: #00cd00;">uint64_t</span> <span style="color: #cdcd00;">T_us</span> = (<span style="color: #00cd00;">uint64_t</span>)(1e6 / 58.); <span style="color: #00cdcd; font-weight: bold;">const</span> <span style="color: #00cd00;">uint64_t</span> <span style="color: #cdcd00;">t0</span> = gettimeofday_uint64(); <span style="color: #00cdcd; font-weight: bold;">for</span>(<span style="color: #00cd00;">int</span> <span style="color: #cdcd00;">i</span>=0; ; i++) { <span style="color: #00cdcd; font-weight: bold;">const</span> <span style="color: #00cd00;">uint64_t</span> <span style="color: #cdcd00;">t_target</span> = t0 + T_us*i; <span style="color: #00cdcd; font-weight: bold;">const</span> <span style="color: #00cd00;">uint64_t</span> <span style="color: #cdcd00;">t1</span> = gettimeofday_uint64(); <span style="color: #00cdcd; font-weight: bold;">if</span>(t_target > t1) usleep(t_target - t1); write(fd, &((<span style="color: #00cd00;">char</span>){<span style="color: #00cd00;">'\xff'</span>}), 1); } <span style="color: #00cdcd; font-weight: bold;">return</span> 0; } </pre> </div> <p> This tries to make sure that each <code>write()</code> call happens at 58Hz. I need these pulses to be regular, so I need to also make sure that the time between each userspace <code>write()</code> and when the edge actually hits the line is as short as possible or, at least, stable. </p> <p> Potential reasons for timing errors: </p> <ol class="org-ol"> <li>The <code>usleep()</code> doesn't wake up exactly when it should. This is subject to the Linux scheduler waking up the <code>trigger</code> process </li> <li>The <code>write()</code> almost certainly ends up scheduling a helper task to actually write the <code>\xFF</code> to the hardware. This helper task is also subject to the Linux scheduler waking it up. </li> <li>Whatever the hardware does. RS-232 doesn't give you any guarantees about byte-byte timings, so this could be an unfixable source of errors </li> </ol> <p> The scheduler-related questions are observable without any extra hardware, so let's do that first. </p> <p> I run the <code>./trigger</code> program, and look at diagnostics while that's running. </p> <p> I look at some device details: </p> <pre class="example"># ls -lh /dev/ttyS0 crw-rw---- 1 root dialout 4, 64 Mar 6 18:11 /dev/ttyS0 # ls -lh /sys/dev/char/4:64/ total 0 -r--r--r-- 1 root root 4.0K Mar 6 16:51 close_delay -r--r--r-- 1 root root 4.0K Mar 6 16:51 closing_wait -rw-r--r-- 1 root root 4.0K Mar 6 16:51 console -r--r--r-- 1 root root 4.0K Mar 6 16:51 custom_divisor -r--r--r-- 1 root root 4.0K Mar 6 16:51 dev lrwxrwxrwx 1 root root 0 Mar 6 16:51 device -> ../../../0000:00:16.3:0.0 -r--r--r-- 1 root root 4.0K Mar 6 16:51 flags -r--r--r-- 1 root root 4.0K Mar 6 16:51 iomem_base -r--r--r-- 1 root root 4.0K Mar 6 16:51 iomem_reg_shift -r--r--r-- 1 root root 4.0K Mar 6 16:51 io_type -r--r--r-- 1 root root 4.0K Mar 6 16:51 irq -r--r--r-- 1 root root 4.0K Mar 6 16:51 line -r--r--r-- 1 root root 4.0K Mar 6 16:51 port drwxr-xr-x 2 root root 0 Mar 6 16:51 power -rw-r--r-- 1 root root 4.0K Mar 6 16:51 rx_trig_bytes lrwxrwxrwx 1 root root 0 Mar 6 16:51 subsystem -> ../../../../../../../class/tty -r--r--r-- 1 root root 4.0K Mar 6 16:51 type -r--r--r-- 1 root root 4.0K Mar 6 16:51 uartclk -rw-r--r-- 1 root root 4.0K Mar 6 16:51 uevent -r--r--r-- 1 root root 4.0K Mar 6 16:51 xmit_fifo_size </pre> <p> Unsurprisingly, this is a part of the <code>tty</code> subsystem. I don't want to spend the time to really figure out how this works, so let me look at <i>all</i> the <code>tty</code> kernel calls and also at all the kernel tasks scheduled by the <code>trigger</code> process, since I suspect that the actual hardware poke is happening in a helper task. I see this: </p> <pre class="example"># bpftrace -e 'k:*tty* /comm=="trigger"/ { printf("%d %d %s\n",pid,tid,probe); } t:sched:sched_wakeup /comm=="trigger"/ { printf("switching to %s(%d); current backtrace:", args.comm, args.pid); print(kstack()); }' ... 3397345 3397345 kprobe:tty_ioctl 3397345 3397345 kprobe:tty_check_change 3397345 3397345 kprobe:__tty_check_change 3397345 3397345 kprobe:tty_wait_until_sent 3397345 3397345 kprobe:tty_write 3397345 3397345 kprobe:file_tty_write.isra.0 3397345 3397345 kprobe:tty_ldisc_ref_wait 3397345 3397345 kprobe:n_tty_write 3397345 3397345 kprobe:tty_hung_up_p switching to kworker/0:1(3400169); current backtrace: ttwu_do_activate+268 ttwu_do_activate+268 try_to_wake_up+605 kick_pool+92 __queue_work.part.0+582 queue_work_on+101 rpm_resume+1398 __pm_runtime_resume+75 __uart_start+85 uart_write+150 n_tty_write+1012 file_tty_write.isra.0+373 vfs_write+656 ksys_write+109 do_syscall_64+130 entry_SYSCALL_64_after_hwframe+118 3397345 3397345 kprobe:tty_update_time 3397345 3397345 kprobe:tty_ldisc_deref ... repeated with each pulse ... </pre> <p> Looking at the sources I see that <code>uart_write()</code> calls <code>__uart_start()</code>, which schedules a task to call <code>serial_port_runtime_resume()</code> which eventually calls <code>serial8250_tx_chars()</code>, which calls some low-level functions to actually send the bits. </p> <p> I look at the time between two of those calls to quantify the scheduler latency: </p> <div class="org-src-container"> <pre class="src src-sh"><span style="color: #cdcd00;">pulserate</span>=58 sudo zsh -c <span style="color: #00cd00;">\</span> <span style="color: #00cd00;">'( echo "# dt_write_ns dt_task_latency_ns";</span> <span style="color: #00cd00;"> bpftrace -q -e "k:vfs_write /comm==\"trigger\" && arg2==1/</span> <span style="color: #00cd00;"> {\$t=nsecs(); if(@t0) { @dt_write = \$t-@t0; } @t0=\$t;}</span> <span style="color: #00cd00;"> k:serial8250_tx_chars /@dt_write/</span> <span style="color: #00cd00;"> {\$t=nsecs(); printf(\"%d %d\\n\", @dt_write, \$t-@t0);}"</span> <span style="color: #00cd00;"> )'</span> <span style="color: #00cd00;">\</span> | vnl-filter <span style="color: #00cd00;">\</span> --stream -p <span style="color: #cdcd00;">dt_write_ms</span>=<span style="color: #00cd00;">"dt_write_ns/1e6 - 1e3/$pulserate"</span>,<span style="color: #cdcd00;">dt_task_latency_ms</span>=dt_task_latency_ns/1e6 <span style="color: #00cd00;">\</span> | feedgnuplot <span style="color: #00cd00;">\</span> --stream <span style="color: #00cd00;">\</span> --lines <span style="color: #00cd00;">\</span> --points <span style="color: #00cd00;">\</span> --xlen 200 <span style="color: #00cd00;">\</span> --vnl <span style="color: #00cd00;">\</span> --autolegend <span style="color: #00cd00;">\</span> --xlabel <span style="color: #00cd00;">'Pulse index'</span> <span style="color: #00cd00;">\</span> --ylabel <span style="color: #00cd00;">'Latency (ms)'</span> </pre> </div> <p> Here I'm making a realtime plot showing </p> <ul class="org-ul"> <li>The offset from 58Hz of when each <code>write()</code> call happens. This shows effect #1 from above: how promptly the <code>trigger</code> process wakes up </li> <li>The latency of the helper task. This shows effect #2 above. </li> </ul> <p> The raw data as I tweak things lives <a href="https://notes.secretsauce.net/../../../notes/2025/03/14_getting-precise-timings-out-of-rs-232-output/timings.scheduler.vnl">here</a>. Initially I see big latency spikes: </p> <div class="figure"> <p><img alt="timings.scheduler.1.noise.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/14_getting-precise-timings-out-of-rs-232-output/timings.scheduler.1.noise.svg" width="80%" /> </p> </div> <p> These can be fixed by adjusting the priority of the <code>trigger</code> task. This tells the scheduler to wake that task up <i>first</i>, even if something else is currently using the CPU. I do this: </p> <div class="org-src-container"> <pre class="src src-sh">sudo chrt -p 90 <span style="color: #cdcd00;">`pidof trigger`</span> </pre> </div> <p> And I get better-looking latencies: </p> <div class="figure"> <p><img alt="timings.scheduler.2.clean.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/14_getting-precise-timings-out-of-rs-232-output/timings.scheduler.2.clean.svg" width="80%" /> </p> </div> <p> During some experiments (not in this dataset) I would see high helper-task timing instabilities as well. These could be fixed by prioritizing the helper task. In this kernel (<code>6.12</code>) the helper task is called <code>kworker/N</code> where <code>N</code> is the CPU index. I tie the <code>trigger</code> process to cpu 0, and priorities all the relevant helpers: </p> <div class="org-src-container"> <pre class="src src-sh">taskset -c 0 ./trigger 58 pgrep -f kworker/0 | <span style="color: #00cdcd; font-weight: bold;">while</span> { <span style="color: #0000ee; font-weight: bold;">read</span> pid } { sudo chrt -p 90 $<span style="color: #cdcd00;">pid</span> } </pre> </div> <p> This fixes the helper-task latency spikes. </p> <p> OK, so it looks like on the software side we're good to within 0.1ms of the true period. This is in the ballpark of the precision I need; even this might be too high. It's possible to try to push the software to do better: one could look at the kernel sources a bit more, to do smarter things with priorities or to try an <code>-rt</code> kernel. But all this doesn't matter if the serial hardware adds unacceptable delays. Let's look. </p> <p> Let's look at it with a logic analyzer. I use a saleae logic analyzer with <a href="https://sigrok.org/">sigrok</a>. The tool spits out the samples as it gets them, and an <code>awk</code> script finds the edges and reports the timings to give me a realtime plot. </p> <div class="org-src-container"> <pre class="src src-sh"><span style="color: #cdcd00;">samplerate</span>=500000; <span style="color: #cdcd00;">pulserate</span>=58.; sigrok-cli -c <span style="color: #cdcd00;">samplerate</span>=$<span style="color: #cdcd00;">samplerate</span> -O csv --continuous -C D1 <span style="color: #00cd00;">\</span> | mawk -Winteractive <span style="color: #00cd00;">\</span> <span style="color: #00cd00;">"prev_logic==0 && \$0==1 \</span> <span style="color: #00cd00;"> { </span> <span style="color: #00cd00;"> iedge = NR;</span> <span style="color: #00cd00;"> if(prev_iedge)</span> <span style="color: #00cd00;"> {</span> <span style="color: #00cd00;"> di = iedge -prev_iedge;</span> <span style="color: #00cd00;"> dt = di/$samplerate;</span> <span style="color: #00cd00;"> print(dt*1000);</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> prev_iedge = iedge;</span> <span style="color: #00cd00;"> }</span> <span style="color: #00cd00;"> {</span> <span style="color: #00cd00;"> prev_logic=\$0;</span> <span style="color: #00cd00;"> } "</span> | feedgnuplot --stream --ylabel <span style="color: #00cd00;">'Period (ms)'</span> --equation <span style="color: #00cd00;">"1000./$pulserate title \"True ${pulserate}Hz period\""</span> </pre> </div> <p> On the server I was using (physical RS-232 port, ancient 3.something kernel): </p> <div class="figure"> <p><img alt="timings.hw.serial-server.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/14_getting-precise-timings-out-of-rs-232-output/timings.hw.serial-server.svg" width="80%" /> </p> </div> <p> OK… This is very discrete for some reason, and generally worse than 0.1ms. What about my laptop (physical RS-232 port, recent 6.12 kernel)? </p> <div class="figure"> <p><img alt="timings.hw.serial-laptop.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/14_getting-precise-timings-out-of-rs-232-output/timings.hw.serial-laptop.svg" width="80%" /> </p> </div> <p> Not discrete anymore, but not really any more precise. What about using a usb-serial converter? I expect this to be worse. </p> <div class="figure"> <p><img alt="timings.hw.usbserial.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/14_getting-precise-timings-out-of-rs-232-output/timings.hw.usbserial.svg" width="80%" /> </p> </div> <p> Yeah, looks worse. For my purposes, an accuracy of 0.1ms is marginal, and the hardware adds non-negligible errors. So I cut my losses, and use an external signal generator: </p> <div class="figure"> <p><img alt="timings.hw.generator.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/14_getting-precise-timings-out-of-rs-232-output/timings.hw.generator.svg" width="80%" /> </p> </div> <p> Yeah. That's better, so that's what I use. </p> </div> <p class="date"> <a href="http://notes.secretsauce.net/notes/2025/03/14_getting-precise-timings-out-of-rs-232-output.html">14 March, 2025 12:47PM</a> by Dima Kogan </p> </div> </div> </div> <div class="channel"> <a href="http://www.netfort.gr.jp/~dancer/diary/202503.html.en"> <img class="face" src="heads/dancer.png" width="75" height="97" alt="hackergotchi for Junichi Uekawa" /> </a> <h2 class="planet-title"> <a href="http://www.netfort.gr.jp/~dancer/diary/202503.html.en" title="Dancer's daily hackings">Junichi Uekawa</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03_hide\" onClick=\"exclude( 'http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03_show\" style=\"display:none;\" onClick=\"show( 'http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03" class="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03"> <div class="entry"> <h3 class="entry-title"> <a href="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03">Filing tax this year was really painful.</a> </h3> <div class="content"> Filing tax this year was really painful. But mostly because my home network. It was ipv4 over ipv6 was not working correctly. First I swapped the Router which was trying to reinitialize the MAP-E table every time there was a dhcp client reconfiguration and overwhelming the server. Then I changed the DNS configuration not use ipv4 UDP lookup which was overwhelming the ipv4 ports. Tax return itself is a painful process. Debugging network issues is making things was just making everything more painful. <p></p> </div> <p class="date"> <a href="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-14.html.en#2025-Mar-14-10:27:03">14 March, 2025 01:27AM</a> by Junichi Uekawa </p> </div> </div> </div> <h1>March 11, 2025</h1> <div class="channel"> <a href="https://www.freexian.com/tags/planet-debian/"> <img class="face" src="heads/freexian.png" width="215" height="101" alt="hackergotchi for Freexian Collaborators" /> </a> <h2 class="planet-title"> <a href="https://www.freexian.com/tags/planet-debian/" title="planet-debian on Freexian">Freexian Collaborators</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://www.freexian.com/blog/debian-contributions-02-2025/_hide\" onClick=\"exclude( 'https://www.freexian.com/blog/debian-contributions-02-2025/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://www.freexian.com/blog/debian-contributions-02-2025/_show\" style=\"display:none;\" onClick=\"show( 'https://www.freexian.com/blog/debian-contributions-02-2025/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://www.freexian.com/blog/debian-contributions-02-2025/" class="https://www.freexian.com/blog/debian-contributions-02-2025/"> <div class="entry"> <h3 class="entry-title"> <a href="https://www.freexian.com/blog/debian-contributions-02-2025/">Debian Contributions: Debian.Social administration, DebConf 25 preparations, Fixing Time-based test failure in Python requests package and more! (by Anupa Ann Joseph)</a> </h3> <div class="content"> <h1 id="debian-contributions-2025-02">Debian Contributions: 2025-02</h1> <p><a href="https://www.freexian.com/about/debian-contributions/">Contributing to Debian</a> is part of <a href="https://www.freexian.com/about/">Freexian’s mission</a>. This article covers the latest achievements of Freexian and their collaborators. All of this is made possible by organizations subscribing to our <a href="https://www.freexian.com/lts/">Long Term Support contracts</a> and <a href="https://www.freexian.com/services/">consulting services</a>.</p> <h2 id="debiansocial-administration-by-stefano-rivera">Debian.Social administration, by Stefano Rivera</h2> <p>Over the last year, the <a href="https://wiki.debian.org/Teams/DebianSocial">Debian.social services</a> outgrew the infrastructure that was supporting them. The matrix bridge in particular was hosted on a cloud instance backed by a large expensive storage volume. Debian.CH rented a new large physical server to host all these instances, earlier this year. Stefano set up <a href="https://linuxcontainers.org/incus/">Incus</a> on the new physical machine and migrated all the old debian.social LXC Containers, libvirt VMs, and cloud instances into Incus-managed LXC containers.</p> <p>Stefano set up Prometheus monitoring and alerts for the new infrastructure and a <a href="https://grafana.debian.social/">Grafana dashboard</a>. The current stack of debian.social services seem to comfortably fit on the new machine, with good room to grow.</p> <h2 id="debconf-25-by-santiago-ruano-rincón-and-stefano-rivera">DebConf 25, by Santiago Ruano Rincón and Stefano Rivera</h2> <p>DebConf 25 preparations continue. The team is currently finalizing a budget. Stefano helped to review the current budget proposals and suggest approaches for balancing it.</p> <p>Stefano installed <a href="https://help.debconf.org/">a Zammad instance</a> to organize queries from attendees, for the registration and visa teams.</p> <p>Santiago continued discussions with possible caterers so we can have options for the different diet requirements and that could fit into the DebConf budget. Also, in collaboration with Anupa, Santiago pushed the first <a href="https://salsa.debian.org/debconf-team/public/websites/dc25/-/merge_requests/7">draft changes</a> to document the venue information in the DebConf 25 website and how to get to Brest.</p> <h2 id="time-based-test-failure-in-requests-by-colin-watson">Time-based test failure in requests, by Colin Watson</h2> <p>Colin fixed a fun bug in the Python <a href="https://requests.readthedocs.io/en/latest/">requests</a> package. Santiago Vila has been <a href="https://lists.debian.org/debian-devel/2024/05/msg00414.html">running tests</a> of what happens when Debian packages are built on a system in which time has been artificially set to somewhere around the end of the support period for the next Debian release, in order to make it easier to do things like issuing security updates for the lifetime of that release. In this case, the <a href="https://bugs.debian.org/1091503">failure</a> indicated an expired test certificate, and since the repository already helpfully included scripts to regenerate those certificates, it seemed natural to try regenerating them just before running tests. However, this <a href="https://github.com/psf/requests/issues/6896">failed</a> for more obscure reasons and Colin spent some time investigating. This turned out to be because the test CA was missing the CA constraint and so recent versions of OpenSSL reject it; Colin sent a <a href="https://github.com/psf/requests/pull/6897">pull request</a> to fix this.</p> <h2 id="priority-list-for-outdated-packages-by-santiago-ruano-rincón">Priority list for outdated packages, by Santiago Ruano Rincón</h2> <p>Santiago started a <a href="https://lists.debian.org/debian-devel/2025/02/msg00134.html">discussion</a> on debian-devel about packages that have a history of security issues and that are outdated regarding new upstream releases. The goal of the mentioned effort is to have a prioritized list of packages needing some work, from a security point of view. Moreover, the aim of publicly sharing the list of packages with the Debian Developers community is to make it easier to look at the packages maintained by teams, or even other maintainers’ where help could be welcome. Santiago is planning to take into account the feedback provided in debian-devel and to propose a tooling that could help to regularly bring collective awareness of these packages.</p> <h2 id="miscellaneous-contributions">Miscellaneous contributions</h2> <ul> <li>Carles worked on English to Catalan po-debconf translations: reviewed translations, created merge requests and followed up with developers for more than 30 packages using po-debconf-manager.</li> <li>Carles helped users, fixed bugs and implemented downloading updated templates on po-debconf-manager.</li> <li>Carles packaged a new upstream version of python-pyaarlo.</li> <li>Carles improved reproducibility of qnetload (now reported as reproducible) and simplemonitor (followed up with upstream and pending update of Debian package).</li> <li>Carles collaborated with debian-history package: fixed FTBFS from master branch, enabled salsa-ci and investigated reproducibility.</li> <li>Emilio improved support for automatically marking CVEs as NOT-FOR-US in the security-tracker, closing <a href="https://bugs.debian.org/1073012">#1073012</a>.</li> <li>Emilio updated xorg-server and xwayland in unstable, fixing the last round of security vulnerabilities.</li> <li>Stefano prepared a few PyPy and cPython uploads, and started the <a href="https://release.debian.org/transitions/html/python3.13-only.html">python3.13-only transition</a>.</li> <li>Helmut Grohne sent patches for 24 cross build failures.</li> <li>Helmut fixed two problems in the Debian /usr-merge analysis tool. In one instance, it would overmatch Debian bugs to issues and in another it would fail to recognize <code>Pre-Depends</code> as a conflict mechanism.</li> <li>Helmut attempted making rebootstrap work for gcc-15 with limited success as very many packages FTBFS with gcc-15 due to using function declarations without arguments.</li> <li>Helmut provided a change to the <code>security-tracker</code> that would pre-compute <code>/data/json</code> during database updates rather than on demand resulting in a reduced response time.</li> <li>Colin uploaded <a href="https://www.openssh.com/releasenotes.html#9.9p2">OpenSSH security updates</a> for testing/unstable, bookworm, bullseye, buster, and stretch.</li> <li>Colin fixed <a href="https://wiki.debian.org/debian/watch">upstream monitoring</a> for 26 Python packages, and upgraded 54 packages (mostly Python-related, but also PuTTY) to new upstream versions.</li> <li>Colin updated python-django in bookworm-backports to 4.2.18 (issuing <a href="https://backports.debian.org/news/BSA-121_Security_Update_for_python-django/">BSA-121</a>), and added new backports of python-django-dynamic-fixture and python-django-pgtrigger, all of which are dependencies of <a href="https://freexian-team.pages.debian.net/debusine/">debusine</a>.</li> <li>Thorsten Alteholz finally managed to upload hplip to fix two release critical and some normal bugs. The next step in March would be to upload the latest version of hplip.</li> <li>Faidon updated crun in unstable & trixie, resolving a long-standing request of enabling criu support and thus enabling podman with checkpoint/restore functionality (With gratitude to Salvatore Bonaccorso and Reinhard Tartler for the cooperation and collaboration).</li> <li>Faidon uploaded a number of packages (librdkafka, libmaxminddb, python-maxminddb, lowdown, tox, tox-uv, pyproject-api, xiccd and gdnsd) bringing them up to date with new upstream releases, resolving various bugs.</li> <li>Lucas Kanashiro uploaded some ruby packages involved in the Rails 7 transition with new upstream releases.</li> <li>Lucas triaged a ruby3.1 bug (<a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1092595">#1092595)</a>) and prepared a fix for the next stable release update.</li> <li>Lucas set up the needed wiki pages and updated the Debian Project status in the Outreachy portal, in order to send out a call for projects and mentors for the next round of Outreachy.</li> <li>Anupa joined Santiago to prepare a list of companies to contact via LinkedIn for DebConf 25 sponsorship.</li> <li>Anupa printed Debian stickers and sponsorship brochures, flyers for DebConf 25 to be distributed at FOSS ASIA summit 2025.</li> <li>Anupa participated in the Debian publicity team meeting and discussed the upcoming events and tasks.</li> <li>Raphaël packaged zim 0.76.1 and integrated an upstream patch for another regression that he reported.</li> <li>Raphaël worked with the Debian System Administrators for tracker.debian.org to better cope with gmail’s requirement for mails to be authenticated.</li> </ul> </div> <p class="date"> <a href="https://www.freexian.com/blog/debian-contributions-02-2025/">11 March, 2025 12:00AM</a> by Anupa Ann Joseph </p> </div> </div> </div> <h1>March 10, 2025</h1> <div class="channel"> <a href="https://www.joachim-breitner.de/blog"> <img class="face" src="heads/nomeata.png" width="64" height="64" alt="hackergotchi for Joachim Breitner" /> </a> <h2 class="planet-title"> <a href="https://www.joachim-breitner.de/blog" title="nomeata’s mind shares">Joachim Breitner</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean_hide\" onClick=\"exclude( 'https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean_show\" style=\"display:none;\" onClick=\"show( 'https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean" class="https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean"> <div class="entry"> <h3 class="entry-title"> <a href="https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean">Extrinsic termination proofs for well-founded recursion in Lean</a> </h3> <div class="content"> <p>A few months ago <a href="https://www.joachim-breitner.de/blog/813-Blogging_on_Lean">I explained</a> that one reason why this blog has become more quiet is that all my work on Lean is covered elsewhere.</p> <p>This post is an exception, because it is an observation that is (arguably) interesting, but does not lead anywhere, so where else to put it than my own blog…</p> <p>Want to share your thoughts about this? Please <a href="https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Extrinsic.20termination.20proofs.20for.20well-founded.20recursion">join the discussion on the Lean community zulip</a>!</p> <h3 id="background">Background</h3> <p>When defining a function recursively in Lean that has <em>nested recursion</em>, e.g. a recusive call that is in the argument to a higher-order function like <code>List.map</code>, then extra attention used to be necessary so that Lean can see that <code>xs.map</code> applies its argument only elements of the list <code>xs</code>. The usual idiom is to write <code>xs.attach.map</code> instead, where <a href="https://leanprover-community.github.io/mathlib4_docs/Init/Data/List/Attach.html#List.attach"><code>List.attach</code></a> attaches to the list elements a proof that they are in that list. You can read more about this my <a href="https://lean-lang.org/blog/2024-1-11-recursive-definitions-in-lean/">Lean blog post on recursive definitions</a> and our <a href="https://lean-lang.org/doc/reference/latest/Recursive-Definitions/Well-Founded-Recursion/#well-founded-recursion">new shiny reference manual</a>, look for Example “Nested Recursion in Higher-order Functions”.</p> <p>To make this step less tedious I taught Lean to automatically rewrite <code>xs.map</code> to <code>xs.attach.map</code> (where suitable) within the construction of well-founded recursion, so that nested recursion just works (<a href="https://github.com/leanprover/lean4/issues/5471">issue #5471</a>). We already do such a rewriting to change <code>if c then … else …</code> to the dependent <code>if h : c then … else …</code>, but the attach-introduction is much more ambitious (the rewrites are not definitionally equal, there are higher-order arguments etc.) Rewriting the terms in a way that we can still prove the connection later when creating the equational lemmas is hairy at best. Also, we want the whole machinery to be extensible by the user, setting up their own higher order functions to add more facts to the context of the termination proof.</p> <p>I implemented it like this (<a href="https://github.com/leanprover/lean4/pull/6744">PR #6744</a>) and it ships with 4.18.0, but in the course of this work I thought about a quite different and maybe better™ way to do this, and well-founded recursion in general:</p> <h3 id="a-simpler-fix">A simpler <code>fix</code></h3> <p>Recall that to use <a href="https://leanprover-community.github.io/mathlib4_docs/Init/WF.html#WellFounded.fix">WellFounded.fix</a></p> <pre class="lean"><code>WellFounded.fix : (hwf : WellFounded r) (F : (x : α) → ((y : α) → r y x → C y) → C x) (x : α) : C x</code></pre> <p>we have to rewrite the functorial of the recursive function, which naturally has type</p> <pre class="lean"><code>F : ((y : α) → C y) → ((x : α) → C x)</code></pre> <p>to the one above, where all recursive calls take the termination proof <code>r y x</code>. This is a fairly hairy operation, mangling the type of matcher’s motives and whatnot.</p> <p>Things are simpler for recursive definitions using <a href="https://lean-lang.org/doc/reference/latest/Recursive-Definitions/Partial-Fixpoint-Recursion/#partial-fixpoint">the new <code>partial_fixpoint</code> machinery</a>, where we use <a href="https://leanprover-community.github.io/mathlib4_docs/Init/Internal/Order/Basic.html#Lean.Order.fix">Lean.Order.fix</a></p> <pre class="lean"><code>Lean.Order.fix : [CCPO α] (F : β → β) (hmono : monotone F) : β</code></pre> <p>so the functorial’s type is unmodified (here <code>β</code> will be <code>((x : α) → C x)</code>), and everything else is in the propositional side-condition <code>montone F</code>. For this predicate we have a syntax-guided compositional tactic, and it’s easily extensible, e.g. by</p> <pre class="lean"><code>theorem monotone_mapM (f : γ → α → m β) (xs : List α) (hmono : monotone f) : monotone (fun x => xs.mapM (f x)) </code></pre> <p>Once given, we don’t care about the content of that proof. In particular proving the unfolding theorem only deals with the unmodified <code>F</code> that closely matches the function definition as written by the user. Much simpler!</p> <h3 id="isabelle-has-it-easier">Isabelle has it easier</h3> <p><a href="https://isabelle.in.tum.de/">Isabelle</a> also supports well-founded recursion, and has great support for nested recursion. And it’s much simpler!</p> <p>There, all you have to do to make nested recursion work is to define a congruence lemma of the form, for <code>List.map</code> something like our <a href="https://leanprover-community.github.io/mathlib4_docs/Init/Data/List/Lemmas.html#List.map_congr_left">List.map_congr_left</a></p> <pre class="lean"><code>List.map_congr_left : (h : ∀ a ∈ l, f a = g a) : List.map f l = List.map g l</code></pre> <p>This is because in Isabelle, too, the termination proofs is a side-condition that essentially states “the functorial <code>F</code> calls its argument <code>f</code> only on smaller arguments”.</p> <h3 id="can-we-have-it-easy-too">Can we have it easy, too?</h3> <p>I had wished we could do the same in Lean for a while, but that form of congruence lemma just isn’t strong enough for us.</p> <p>But maybe there is a way to do it, using an existential to give a witness that <code>F</code> can alternatively implemented using the more restrictive argument. The following <code>callsOn P F</code> predicate can express that <code>F</code> calls its higher-order argument only on arguments that satisfy the predicate <code>P</code>:</p> <pre class="lean"><code>section setup variable {α : Sort u} variable {β : α → Sort v} variable {γ : Sort w} def callsOn (P : α → Prop) (F : (∀ y, β y) → γ) := ∃ (F': (∀ y, P y → β y) → γ), ∀ f, F' (fun y _ => f y) = F f variable (R : α → α → Prop) variable (F : (∀ y, β y) → (∀ x, β x)) local infix:50 " ≺ " => R def recursesVia : Prop := ∀ x, callsOn (· ≺ x) (fun f => F f x) noncomputable def fix (wf : WellFounded R) (h : recursesVia R F) : (∀ x, β x) := wf.fix (fun x => (h x).choose) def fix_eq (wf : WellFounded R) h x : fix R F wf h x = F (fix R F wf h) x := by unfold fix rw [wf.fix_eq] apply (h x).choose_spec</code></pre> <p>This allows nice compositional lemmas to discharge <code>callsOn</code> predicates:</p> <pre class="lean"><code>theorem callsOn_base (y : α) (hy : P y) : callsOn P (fun (f : ∀ x, β x) => f y) := by exists fun f => f y hy intros; rfl @[simp] theorem callsOn_const (x : γ) : callsOn P (fun (_ : ∀ x, β x) => x) := ⟨fun _ => x, fun _ => rfl⟩ theorem callsOn_app {γ₁ : Sort uu} {γ₂ : Sort ww} (F₁ : (∀ y, β y) → γ₂ → γ₁) -- can this also support dependent types? (F₂ : (∀ y, β y) → γ₂) (h₁ : callsOn P F₁) (h₂ : callsOn P F₂) : callsOn P (fun f => F₁ f (F₂ f)) := by obtain ⟨F₁', h₁⟩ := h₁ obtain ⟨F₂', h₂⟩ := h₂ exists (fun f => F₁' f (F₂' f)) intros; simp_all theorem callsOn_lam {γ₁ : Sort uu} (F : γ₁ → (∀ y, β y) → γ) -- can this also support dependent types? (h : ∀ x, callsOn P (F x)) : callsOn P (fun f x => F x f) := by exists (fun f x => (h x).choose f) intro f ext x apply (h x).choose_spec theorem callsOn_app2 {γ₁ : Sort uu} {γ₂ : Sort ww} (g : γ₁ → γ₂ → γ) (F₁ : (∀ y, β y) → γ₁) -- can this also support dependent types? (F₂ : (∀ y, β y) → γ₂) (h₁ : callsOn P F₁) (h₂ : callsOn P F₂) : callsOn P (fun f => g (F₁ f) (F₂ f)) := by apply_rules [callsOn_app, callsOn_const]</code></pre> <p>With this setup, we can have the following, possibly user-defined, lemma expressing that <code>List.map</code> calls its arguments only on elements of the list:</p> <pre class="lean"><code>theorem callsOn_map (δ : Type uu) (γ : Type ww) (P : α → Prop) (F : (∀ y, β y) → δ → γ) (xs : List δ) (h : ∀ x, x ∈ xs → callsOn P (fun f => F f x)) : callsOn P (fun f => xs.map (fun x => F f x)) := by suffices callsOn P (fun f => xs.attach.map (fun ⟨x, h⟩ => F f x)) by simpa apply callsOn_app · apply callsOn_app · apply callsOn_const · apply callsOn_lam intro ⟨x', hx'⟩ dsimp exact (h x' hx') · apply callsOn_const end setup</code></pre> <p>So here is the (manual) construction of a nested <code>map</code> for trees:</p> <pre class="lean"><code>section examples structure Tree (α : Type u) where val : α cs : List (Tree α) -- essentially -- def Tree.map (f : α → β) : Tree α → Tree β := -- fun t => ⟨f t.val, t.cs.map Tree.map⟩) noncomputable def Tree.map (f : α → β) : Tree α → Tree β := fix (sizeOf · < sizeOf ·) (fun map t => ⟨f t.val, t.cs.map map⟩) (InvImage.wf (sizeOf ·) WellFoundedRelation.wf) <| by intro ⟨v, cs⟩ dsimp only apply callsOn_app2 · apply callsOn_const · apply callsOn_map intro t' ht' apply callsOn_base -- ht' : t' ∈ cs -- ! -- ⊢ sizeOf t' < sizeOf { val := v, cs := cs } decreasing_trivial end examples</code></pre> <p>This makes me happy!</p> <p>All details of the construction are now contained in a proof that can proceed by a syntax-driven tactic and that’s easily and (likely robustly) extensible by the user. It also means that we can share a lot of code paths (e.g. everything related to equational theorems) between well-founded recursion and <code>partial_fixpoint</code>.</p> <p>I wonder if this construction is really as powerful as our current one, or if there are certain (likely dependently typed) functions where this doesn’t fit, but the <code>β</code> above is dependent, so it looks good.</p> <p>With this construction, functions defined by well-founded recursion will reduce even worse in the kernel, I assume. <a href="https://github.com/leanprover/lean4/issues/5192">This may be a good thing</a>.</p> <h3 id="the-cake-is-a-lie">The cake is a lie</h3> <p>What unfortunately kills this idea, though, is the generation of the <a href="https://lean-lang.org/blog/2024-5-17-functional-induction/">functional induction principles</a>, which I believe is not (easily) possible with this construction: The functional induction principle is proved by massaging <code>F</code> to return a proof, but since the extra assumptions (e.g. for <code>ite</code> or <code>List.map</code>) only exist in the termination proof, they are not available in <code>F</code>.</p> <p>Oh wey, how anticlimactic.</p> <h3 id="ps-path-dependencies">PS: Path dependencies</h3> <p>Curiously, if we didn’t have functional induction at this point yet, then very likely I’d change Lean to use this construction, and then we’d either not get functional induction, or it would be implemented very differently, maybe a more syntactic approach that would re-prove termination. I guess that’s called path dependence.</p> </div> <p class="date"> <a href="https://www.joachim-breitner.de/blog/816-Extrinsic_termination_proofs_for_well-founded_recursion_in_Lean">10 March, 2025 05:47PM</a> by Joachim Breitner (mail@joachim-breitner.de) </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="http://blog.alteholz.eu" title="planetdebian – blog.alteholz.eu">Thorsten Alteholz</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/_hide\" onClick=\"exclude( 'http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/_show\" style=\"display:none;\" onClick=\"show( 'http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/" class="http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/"> <div class="entry"> <h3 class="entry-title"> <a href="http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/">My Debian Activities in February 2025</a> </h3> <div class="content"> <h3><strong>Debian LTS</strong></h3> <p>This was my hundred-twenty-eighth month that I did some work for the Debian LTS initiative, started by Raphael Hertzog at Freexian. During my allocated time I uploaded or worked on: </p> <ul><li>[<a href="https://lists.debian.org/debian-lts-announce/2025/02/msg00036.html">DLA 4072-1</a>] xorg-server security update to fix eight CVEs related to possible privilege escalation in X.</li><li>[<a href="http://blog.alteholz.eu/tag/planetdebian/feed/">DLA 4073-1</a>] ffmpeg security update to fix three CVEs related to out-of-bounds read, assert errors and NULL pointer dereferences. This was the second update that I announced last month.</li></ul> <p>Last but not least I did some days of FD this month and attended the monthly LTS/ELTS meeting.</p> <h3><strong>Debian ELTS</strong></h3> <p>This month was the seventy-ninth ELTS month. During my allocated time I uploaded or worked on: </p> <ul><li>[ELA-1337-1] xorg-server security update to fix eight CVEs in Buster, Stretch and Jessie, related to possible privilege escalation in X. </li><li>[ELA-882-2] amanda regression update to improve a fix for privilege escalation. This old regression was detected by Beuc during his work as FD and now finally fixed. </li></ul> <p>Last but not least I did some days of FD this month and attended the monthly LTS/ELTS meeting.</p> <h3><strong>Debian Printing</strong></h3> <p>This month I uploaded new packages or new upstream or bugfix versions of:</p> <ul><li>… <a href="https://tracker.debian.org/hplip">hplip</a> to fix some bugs and let hplip migrate to testing again.</li></ul> <p><strong>This work is generously funded by <a href="https://www.freexian.com">Freexian</a>!</strong></p> <h3><strong>Debian Matomo</strong></h3> <p>This month I uploaded new packages or new upstream or bugfix versions of:</p> <ul><li>… <a href="https://tracker.debian.org/php-jshrink">php-jshrink</a></li><li>… <a href="https://tracker.debian.org/php-maxmind-web-service-common">php-maxmind-web-service-common</a></li><li>… <a href="https://tracker.debian.org/php-sparkline">php-sparkline</a></li><li>… <a href="https://tracker.debian.org/php-spy">php-spyc</a></li></ul> <p>Finally <i>matomo</i> was uploaded. Thanks a lot to Utkarsh Gupta and William Desportes for doing most of the work to make this happen.</p> <p><strong>This work is generously funded by <a href="https://www.freexian.com">Freexian</a>!</strong></p> <h3><strong>Debian Astro</strong></h3> <p></p><p>Unfortunately I didn’t found any time to upload packages.</p><p>Have you ever heard of <i>poliastro</i>? It was a package to do calculations related to astrodynamics and orbital mechanics? It was archived by upstream end of 2023. I am now trying to revive it under the new name <i>boinor</i> and hope to get it back into Debian over the next months. </p><p></p> <p>This is almost the last month that Patrick, our Outreachy intern for the Debian Astro project, is handling his tasks. He is working on automatic updates of the indi 3rd-party driver.</p> <h3><strong>Debian IoT</strong></h3> <p>Unfortunately I didn’t found any time to work on this topic.</p> <h3><strong>Debian Mobcom</strong></h3> <p>This month I uploaded new packages or new upstream or bugfix versions of:</p> <ul><li>… <a href="https://tracker.debian.org/osmocom-dahdi-linux">osmocom-dahdi-linux</a> fixing bugs</li><li>… <a href="https://tracker.debian.org/libosmo-sccp">libosmo-abis</a> fixing more bugs</li></ul> <h3><strong>misc</strong></h3> <p>Unfortunately I didn’t found any time to work on this topic.</p> <h3><strong>FTP master</strong></h3> <p>This month I accepted 437 and rejected 64 packages. The overall number of packages that got accepted was 445.</p> </div> <p class="date"> <a href="http://blog.alteholz.eu/2025/03/my-debian-activities-in-february-2025/">10 March, 2025 03:33PM</a> by alteholz </p> </div> </div> </div> <h1>March 09, 2025</h1> <div class="channel"> <a href="http://dirk.eddelbuettel.com/blog"> <img class="face" src="heads/dirk.png" width="65" height="90" alt="hackergotchi for Dirk Eddelbuettel" /> </a> <h2 class="planet-title"> <a href="http://dirk.eddelbuettel.com/blog" title="Thinking inside the box">Dirk Eddelbuettel</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2_hide\" onClick=\"exclude( 'http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2_show\" style=\"display:none;\" onClick=\"show( 'http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2" class="http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2"> <div class="entry"> <h3 class="entry-title"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2">RcppNLoptExample 0.0.2: Minor Updates</a> </h3> <div class="content"> <p>An update to our package <a href="https://dirk.eddelbuettel.com/code/rcpp.nloptexample.html">RcppNLoptExample</a> arrived on <a href="https://cran.r-project.org">CRAN</a> earlier today marking the first update since the <a href="https://dirk.eddelbuettel.com/blog/2018/10/13#rcppnloptexample_0.0.1">intial release</a> more than four year ago. The <a href="https://github.com/jyypma/nloptr">nloptr</a> package, created by <a href="https://github.com/jyypma">Jelmer Ypma</a>, has long been providing an excellent R interface to <a href="https://nlopt.readthedocs.io/en/latest/">NLopt</a>, a very comprehensive library for nonlinear optimization. In particular, <a href="https://github.com/jyypma">Jelmer</a> carefully exposed the API entry points such that other R packages can rely on <a href="https://nlopt.readthedocs.io/en/latest/">NLopt</a> without having to <em>explicitly</em> link to it (as one can rely on R providing sufficient function calling and registration to make this possible by referring back to <a href="https://github.com/jyypma/nloptr">nloptr</a> which naturally has the linking information and resolution). This package demonstrates this in a simple-to-use <a href="https://www.rcpp.org">Rcpp</a> example package that can serve as a stanza.</p> <p>More recent <a href="https://nlopt.readthedocs.io/en/latest/">NLopt</a> versions appear to have changed behaviour a little so that an example we relied upon in simple unit test now converges to a marginally different numerical value, so we adjusted a convergence treshold. Other than that we did a number of the usual small updates to package metadata, to the README.md file, and to continuous integration.</p> <p>The (very short) NEWS entry follows:</p> <blockquote> <h4 id="changes-in-version-0.0.2-2025-03-09">Changes in version 0.0.2 (2025-03-09)</h4> <ul> <li><p>Updated tolerance in simple test as newer upstream <span class="pkg">nlopt</span> change behaviour ever so slightly leading to an other spurious failure</p></li> <li><p>Numerous small and standard updates to DESCRIPTION, README.md, badges, and continuous integration setup</p></li> </ul> </blockquote> <p>Courtesy of my <a href="https://dirk.eddelbuettel.com/cranberries/">CRANberries</a>, there is also a diffstat report for <a href="https://dirk.eddelbuettel.com/cranberries/2025/03/09#RcppNLoptExample_0.0.2">this release</a>. For questions, suggestions, or issues please use the <a href="https://github.com/eddelbuettel/rcppnloptexample/issues">issue tracker</a> at the <a href="https://github.com/eddelbuettel/rcppnloptexample">GitHub repo</a>.</p> <p style="font-size: 80%; font-style: italic;"> This post by <a href="https://dirk.eddelbuettel.com">Dirk Eddelbuettel</a> originated on his <a href="https://dirk.eddelbuettel.com/blog/">Thinking inside the box</a> blog. If you like this or other open-source work I do, you can now <a href="https://github.com/sponsors/eddelbuettel">sponsor me at GitHub</a>. </p><p></p> </div> <p class="date"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/09#rcppnloptexample_0.0.2">09 March, 2025 08:06PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="https://perezmeyer.com.ar/"> <img class="face" src="heads/lisandropm.png" width="78" height="100" alt="hackergotchi for Lisandro Damián Nicanor Pérez Meyer" /> </a> <h2 class="planet-title"> <a href="https://perezmeyer.com.ar/" title="Solo sé que se querer, que tengo Dios y tengo fe - planetdebian-en">Lisandro Damián Nicanor Pérez Meyer</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/_hide\" onClick=\"exclude( 'https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/_show\" style=\"display:none;\" onClick=\"show( 'https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/" class="https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/"> <div class="entry"> <h3 class="entry-title"> <a href="https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/">Bahía Blanca floods - Mother nature says: no Nuremberg for you today</a> </h3> <div class="content"> <h2>Update 20250309 13:20-03:00 - How to help</h2> <p>A friend of mine living in the USA sent me this link to help the flood victims: <a href="https://www.zeffy.com/en-US/donation-form/support-bahia-blanca-argentina-flood-victims">Support Bahía Blanca (Argentina) Flood Victims</a></p> <h2>Original blog post</h2> <p>These are not good news. In fact, much the contrary. Compared to the real issue, the fact that I'm not able to attend Embedded World at Nuremberg is, well, a detail. Or at least that's what I'm forcing myself to believe, as I <em>REALLY</em> wanted to be there. But mother nature said otherwise.</p> <p><img alt="Plaza Dr. Alberto Martinelli - Barrio Parque Las Cañitas" src="https://perezmeyer.com.ar/images/bahia_blanca_flood_2025_park.jpg" /></p> <p><a href="https://maps.app.goo.gl/zhBGwzS3yvJKZEGk7">Park "D. Alberto Martinelli", Las Cañitas, Bahía Blanca (Google Maps)</a></p> <p><a href="https://en.wikipedia.org/wiki/Bah%C3%ADa_Blanca">Bahía Blanca </a>, the city I live, has received a lot on rainfall. Really, a lot. Let me introduce the number like this: the previous highest recorded measurement was 170mm (6.69 inch)... in a month. Yesterday Friday 07 we had more than 400mm (15.75 inch) in 9 hours.</p> <p>But those are just numbers. Some things are better seen in images.</p> <p>I'll start with some soft ones.</p> <p><img alt="Streetk sink 1" src="https://perezmeyer.com.ar/images/bahia_blanca_flood_2025_street_sink_1.jpg" title="Street sink in Fournier and Cambaceres, Bahía Blanca" /> <img alt="Streetk sink 2" src="https://perezmeyer.com.ar/images/bahia_blanca_flood_2025_street_sink_2.jpg" title="Street sink in Fournier and Cambaceres, Bahía Blanca" /></p> <p><a href="https://maps.app.goo.gl/H5C8nzYWrYbjVpgy5">Sink in Fournier street near Cambaceres (Google Maps)</a></p> <p>I also happen to do figure skating in the same school of the 4 times world champions (where "world" means the whole world) <a href="https://www.instagram.com/rollerdreamsargentina/?hl=en">Roller Dreams precision skating team - Instagram</a>, from Club El Nacional. Our skating rink got severely damaged with the hail we had like 3 weeks ago (yes, we had hail too!!!). Now it's just impossible:</p> <p><img alt="Roller Dreams CEN skating rink" src="https://perezmeyer.com.ar/images/bahia_blanca_flood_2025_roller_dreams_cen_rink.jpg" /></p> <h2>The "real" thing</h2> <p>Let's get to the heavy, heartbreaker part. I did go to downtown Bahía Blanca, but during night, so let me share some links, most of them in Spanish, but images are images:</p> <ul> <li><a href="https://www.lanueva.com/nota/2025-3-8-8-8-0-el-dia-despues-de-la-catastrofe-bahia-volvio-a-amanecer-destrozada">El día después de la catástrofe: Bahía volvió a amanecer destrozada, La Nueva</a>.</li> <li><a href="https://www.lanueva.com/nota/2025-3-8-19-29-0-en-20-imagenes-el-inmenso-dano-que-provoco-el-temporal-en-bahia">En 20 imágenes, el inmenso daño que provocó el temporal en Bahía, La Nueva</a>.</li> <li><a href="https://www.instagram.com/reel/DG6WWOXy9Cx/?igsh=MWh5ZXVkdzdzdngwaw%3D%3D">Drone footage of the nearby stream, which now seems a river, Instagram</a>.</li> <li><a href="https://vod.apolomedia.com/apolo-vod/gid2/vod/cadena3/cadena3/69/2-8-API-BACG1X1741453528_360P.mp4">Drone footage of the same above stream nearer the golf club and entering the city - MP4</a>. I do not know the author, happy to give the proper credits if contacted!!!</li> </ul> <p>My alma matter, Universidad Nacional del Sur, lost its main library, great part of the Physics department and a lot of labs :-(</p> <p>A nearby town, General Cerri, had even worst luck. In Bahía Blanca, a city of 300k+ people, has around 400 evacuated people. General Cerri, a town of 3000? people, had at least 800.</p> <h2>Bahía Blanca, devil's land</h2> <p>Every place has its legends. We do too. This land was called "Huecuvú Mapú", something like "Devil's land" by the original inhabitants of the zone, due to its harsh climate: string winters and hot summers, couple with fierce wind. But back in 1855 the Cacique (chief) José María Bulnes Yanquetruz had a peace agreement with commander Nicanor Otamendi. But a battle ensued, which Yanquetruz won. At this point history defers depending upon who tells it. Some say Yanquetruz was assigned a military grade as Captain of the indigenous auxiliary forces and provided a military suit, some say he stole it, some say this was a setup of another chief wanting to disrupt peace. But what is known is that Yanquetruz was killed, and his wife, the "machi" (sorceress), issued a curse over the land that would last 1000 years, and the curse was on the climate.</p> <h2>Aftermath</h2> <p>No, we are not there yet. This has just happened. The third violent climate occurrence in 15 months. The city needs to mourn and start healing itself. Time will say.</p> </div> <p class="date"> <a href="https://perezmeyer.com.ar/blog/2025/03/08/bahia-blanca-2025-floods/">09 March, 2025 06:35PM</a> by Lisandro Damián Nicanor Pérez Meyer </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="https://people.debian.org/~nthykier/blog/" title="Things that I work on in Debian - pdo">Niels Thykier</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html_hide\" onClick=\"exclude( 'https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html_show\" style=\"display:none;\" onClick=\"show( 'https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html" class="https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html">Improving Debian packaging in Kate</a> </h3> <div class="content"> <p>The other day, I noted that the <tt class="docutils literal">emacs</tt> integration with <tt class="docutils literal">debputy</tt> stopped working. After debugging for a while, I realized that <tt class="docutils literal">emacs</tt> no longer sent the <tt class="docutils literal">didOpen</tt> notification that is expected of it, which confused <tt class="docutils literal">debputy</tt>. At this point, I was already several hours into the debugging and I noted there was some discussions on <tt class="docutils literal"><span class="pre">debian-devel</span></tt> about <tt class="docutils literal">emacs</tt> and byte compilation not working. So I figured I would shelve the <tt class="docutils literal">emacs</tt> problem for now.</p> <p>But I needed an LSP capable editor and with my <tt class="docutils literal">vi</tt> skills leaving much to be desired, I skipped out on <tt class="docutils literal"><span class="pre">vim-youcompleteme</span></tt>. Instead, I pulled out <tt class="docutils literal">kate</tt>, which I had not been using for years. It had LSP support, so it would fine, right?</p> <p>Well, no. Turns out that <tt class="docutils literal">debputy</tt> LSP support had some assumptions that worked for <tt class="docutils literal">emacs</tt> but not <tt class="docutils literal">kate</tt>. Plus once you start down the rabbit hole, you stumble on things you missed previously.</p> <div class="section" id="getting-started"> <h2>Getting started</h2> <p>First order of business was to tell <tt class="docutils literal">kate</tt> about <tt class="docutils literal">debputy</tt>. Conveniently, <tt class="docutils literal">kate</tt> has a configuration tab for adding language servers in a JSON format right next to the tab where you can see its configuration for built-in LSP (also in JSON format9. So a quick bit of copy-paste magic and that was done.</p> <p>Yesterday, I opened an MR against upstream to have the configuration added (<a class="reference external" href="https://invent.kde.org/utilities/kate/-/merge_requests/1748">https://invent.kde.org/utilities/kate/-/merge_requests/1748</a>) and they already merged it. Today, I then filed a wishlist against <tt class="docutils literal">kate</tt> in Debian to have the Debian maintainers cherry-pick it, so it works out of the box for Trixie (<a class="reference external" href="https://bugs.debian.org/1099876">https://bugs.debian.org/1099876</a>).</p> <p>So far so good.</p> </div> <div class="section" id="inlay-hint-woes"> <h2>Inlay hint woes</h2> <p>Since July (2024), <tt class="docutils literal">debputy</tt> has support for <tt class="docutils literal">Inlay hints</tt>. They are basically small bits of text that the LSP server can ask the editor to inject into the text to provide hints to the reader.</p> <p>Typically, you see them used to provide typing hints, where the editor or the underlying LSP server has figured out the type of a variable or expression that you did not explicitly type. Another common use case is to inject the parameter name for positional arguments when calling a function, so the user do not have to count the position to figure out which value is passed as which parameter.</p> <p>In <tt class="docutils literal">debputy</tt>, I have been using the <tt class="docutils literal">Inlay hints</tt> to show inherited fields in <tt class="docutils literal">debian/control</tt>. As an example, if you have a definition like:</p> <div class="highlight"><pre><span></span>Source: foo-src Section: devel Priority: optional Package: foo-bin Architecture: any </pre></div> <p>Then <tt class="docutils literal"><span class="pre">foo-bin</span></tt> inherits the <tt class="docutils literal">Section</tt> and <tt class="docutils literal">Priority</tt> field since it does not supply its own. Previously, <tt class="docutils literal">debputy</tt> would that by injecting the fields themselves and their value just below the <tt class="docutils literal">Package</tt> field as if you had typed them out directly. The editor always renders <tt class="docutils literal">Inlay hints</tt> distinctly from regular text, so there was no risk of confusion and it made the text look like a valid <tt class="docutils literal">debian/control</tt> file end to end. The result looked something like:</p> <div class="highlight"><pre><span></span>Source: foo-src Section: devel Priority: optional Package: foo-bin Section: devel Priority: optional Architecture: any </pre></div> <p>With the second instances of <tt class="docutils literal">Section</tt> and <tt class="docutils literal">Priority</tt> being rendered differently than its surrendering (usually faded or colorlessly).</p> <p>Unfortunately, <tt class="docutils literal">kate</tt> did not like injecting <tt class="docutils literal">Inlay hints</tt> with a newline in them, which was needed for this trick. Reading into the LSP specs, it says nothing about multi-line <tt class="docutils literal">Inlay hints</tt> being a thing and I figured I would see this problem again with other editors if I left it be.</p> <p>I ended up changing the <tt class="docutils literal">Inlay hints</tt> to be placed at the end of the <tt class="docutils literal">Package</tt> field and then included surrounding <tt class="docutils literal">()</tt> for better visuals. So now, it looks like:</p> <div class="highlight"><pre><span></span>Source: foo-src Section: devel Priority: optional Package: foo-bin (Section: devel) (Priority: optional) Architecture: any </pre></div> <p>Unfortunately, it is no longer 1:1 with the underlying syntax which I liked about the previous one. But it works in more editors and is still explicit. I also removed the <tt class="docutils literal">Inlay hint</tt> for the <tt class="docutils literal">Homepage</tt> field. It takes too much space and I have yet to meet someone missing it in the binary stanza.</p> <p>If you have any better ideas for how to render it, feel free to reach out to me.</p> </div> <div class="section" id="spurious-completion-and-hover"> <h2>Spurious completion and hover</h2> <p>As I was debugging the <tt class="docutils literal">Inlay hints</tt>, I wanted to do a quick restart of <tt class="docutils literal">debputy</tt> after each fix. Then I would trigger a small change to the document to ensure <tt class="docutils literal">kate</tt> would request an update from <tt class="docutils literal">debputy</tt> to render the <tt class="docutils literal">Inlay hints</tt> with the new code.</p> <p>The full outgoing payloads are sent via the logs to the client, so it was really about minimizing which LSP requests are sent to <tt class="docutils literal">debputy</tt>. Notably, two cases would flood the log:</p> <blockquote> <ul class="simple"> <li>Completion requests. These are triggered by typing anything at all and since I wanted to a change, I could not avoid this. So here it was about making sure there would be nothing to complete, so the result was a small as possible.</li> <li>Hover doc requests. These are triggered by mouse hovering over field, so this was mostly about ensuring my mouse movement did not linger over any field on the way between restarting the LSP server and scrolling the log in <tt class="docutils literal">kate</tt>.</li> </ul> </blockquote> <p>In my infinite wisdom, I chose to make a comment line where I would do the change. I figured it would neuter the completion requests completely and it should not matter if my cursor landed on the comment as there would be no hover docs for comments either.</p> <p>Unfortunately for me, <tt class="docutils literal">debputy</tt> would ignore the fact that it was on a comment line. Instead, it would find the next field after the comment line and try to complete based on that. Normally you do not see this, because the editor correctly identifies that none of the completion suggestions start with a <tt class="docutils literal">\#</tt>, so they are all discarded.</p> <p>But it was pretty annoying for the debugging, so now <tt class="docutils literal">debputy</tt> has been told to explicitly stop these requests early on comment lines.</p> </div> <div class="section" id="hover-docs-for-packages"> <h2>Hover docs for packages</h2> <p>I added a feature in <tt class="docutils literal">debputy</tt> where you can hover over package names in your relationship fields (such as <tt class="docutils literal">Depends</tt>) and <tt class="docutils literal">debputy</tt> will render a small snippet about it based on data from your local APT cache.</p> <p>This doc is then handed to the editor and tagged as <tt class="docutils literal">markdown</tt> provided the editor supports <tt class="docutils literal">markdown</tt> rendering. Both <tt class="docutils literal">emacs</tt> and <tt class="docutils literal">kate</tt> support <tt class="docutils literal">markdown</tt>. However, not all <tt class="docutils literal">markdown</tt> renderings are equal. Notably, <tt class="docutils literal">emacs</tt>'s rendering does not reformat the text into paragraphs. In a sense, <tt class="docutils literal">emacs</tt> rendering works a bit like <tt class="docutils literal"><span class="pre"><pre>...</pre></span></tt> except it does a bit of fancy rendering inside the <tt class="docutils literal"><span class="pre"><pre>...</pre></span></tt>.</p> <p>On the other hand, <tt class="docutils literal">kate</tt> seems to convert the <tt class="docutils literal">markdown</tt> to HTML and then throw the result into an HTML render engine. Here it is important to remember that not all newlines are equal in <tt class="docutils literal">markdown</tt>. A <tt class="docutils literal">Foo<newline>Bar</tt> is treated as one "paragraph" (<tt class="docutils literal"><span class="pre"><p>...</p></span></tt>) and the HTML render happily renders this as single line <tt class="docutils literal">Foo Bar</tt> provided there is sufficient width to do so.</p> <p>A couple of extra newlines made wonders for the <tt class="docutils literal">kate</tt> rendering, but I have a feeling this is not going to be the last time the hover docs will need some tweaking for prettification. Feel free to reach out if you spot a weirdly rendered hover doc somewhere.</p> </div> <div class="section" id="making-quickfixes-available-in-kate"> <h2>Making quickfixes available in <tt class="docutils literal">kate</tt></h2> <p>Quickfixes are treated as generic code actions in the LSP specs. Each code action has a "type" (<tt class="docutils literal">kind</tt> in the LSP lingo), which enables the editor to group the actions accordingly or filter by certain types of code actions.</p> <p>The design in the specs leads to the following flow:</p> <blockquote> <ol class="arabic simple"> <li>The LSP server provides the editor with diagnostics (there are multiple ways to trigger this, so we will keep this part simple).</li> <li>The editor renders them to the user and the user chooses to interact with one of them.</li> <li>The interaction makes the editor asks the LSP server, which code actions are available at that location (optionally with filter to only see quickfixes).</li> <li>The LSP server looks at the provided range and is expected to return the relevant quickfixes here.</li> </ol> </blockquote> <p>This flow is really annoying from a LSP server writer point of view. When you do the diagnostics (in step 1), you tend to already know what the possible quickfixes would be. The LSP spec authors realized this at some point, so there are two features the editor provides to simplify this.</p> <blockquote> <ol class="arabic simple"> <li>In the editor request for code actions, the editor is expected to provide the diagnostics that they received from the server. Side note: I cannot quite tell if this is optional or required from the spec.</li> <li>The editor can provide support for remembering a <tt class="docutils literal">data</tt> member in each diagnostic. The server can then store arbitrary information in that member, which they will see again in the code actions request. Again, provided that the editor supports this optional feature.</li> </ol> </blockquote> <p>All the quickfix logic in <tt class="docutils literal">debputy</tt> so far has hinged on both of these two features.</p> <p>As life would have it, <tt class="docutils literal">kate</tt> provides <strong>neither</strong> of them.</p> <p>Which meant I had to teach <tt class="docutils literal">debputy</tt> to keep track of its diagnostics on its own. The plus side is that makes it easier to support "pull diagnostics" down the line, since it requires a similar feature. Additionally, it also means that quickfixes are now available in more editors. For consistency, <tt class="docutils literal">debputy</tt> logic is now always used rather than relying on the editor support when present.</p> <p>The downside is that I had to spend hours coming up with and debugging a way to find the diagnostics that overlap with the range provided by the editor. The most difficult part was keeping the logic straight and getting the runes correct for it.</p> </div> <div class="section" id="making-the-quickfixes-actually-work"> <h2>Making the quickfixes actually work</h2> <p>With all of that, <tt class="docutils literal">kate</tt> would show the quickfixes for diagnostics from <tt class="docutils literal">debputy</tt> and you could use them too. However, they would always apply twice with suboptimal outcome as a result.</p> <p>The LSP spec has multiple ways of defining what need to be changed in response to activating a code action. In <tt class="docutils literal">debputy</tt>, all edits are currently done via the <tt class="docutils literal">WorkspaceEdit</tt> type. It has two ways of defining the changes. Either via <tt class="docutils literal">changes</tt> or <tt class="docutils literal">documentChanges</tt> with <tt class="docutils literal">documentChanges</tt> being the preferred one if both parties support this.</p> <p>I originally read that as I was allowed to provide both and the editor would pick the one it preferred. However, after seeing <tt class="docutils literal">kate</tt> blindly use both when they are present, I reviewed the spec and it does say "The edit should either provide <tt class="docutils literal">changes</tt> or <tt class="docutils literal">documentChanges</tt>", so I think that one is on me.</p> <p>None of the changes in <tt class="docutils literal">debputy</tt> currently require <tt class="docutils literal">documentChanges</tt>, so I went with just using <tt class="docutils literal">changes</tt> for now despite it not being preferred. I cannot figure out the logic of whether an editor supports <tt class="docutils literal">documentChanges</tt>. As I read the notes for this part of the spec, my understanding is that <tt class="docutils literal">kate</tt> does not announce its support for <tt class="docutils literal">documentChanges</tt> but it clearly uses them when present. Therefore, I decided to keep it simple for now until I have time to dig deeper.</p> </div> <div class="section" id="remaining-limitations-with-kate"> <h2>Remaining limitations with <tt class="docutils literal">kate</tt></h2> <p>There is one remaining limitation with <tt class="docutils literal">kate</tt> that I have not yet solved. The <tt class="docutils literal">kate</tt> program uses <tt class="docutils literal">KSyntaxHighlighting</tt> for its language detection, which in turn is the basis for which LSP server is assigned to a given document.</p> <p>This engine does not seem to support as complex detection logic as I hoped from it. Concretely, it either works on matching on an extension / a basename (same field for both cases) or mime type. This combined with our habit in Debian to use extension less files like <tt class="docutils literal">debian/control</tt> vs. <tt class="docutils literal">debian/tests/control</tt> or <tt class="docutils literal">debian/rules</tt> or <tt class="docutils literal">debian/upstream/metadata</tt> makes things awkward a best.</p> <p>Concretely, the syntax engine cannot tell <tt class="docutils literal">debian/control</tt> from <tt class="docutils literal">debian/tests/control</tt> as they use the same basename. Fortunately, the syntax is close enough to work for both and <tt class="docutils literal">debputy</tt> is set to use filename based lookups, so this case works well enough.</p> <p>However, for <tt class="docutils literal">debian/rules</tt> and <tt class="docutils literal">debian/upstream/metadata</tt>, my understanding is that if I assign these in the syntax engine as Debian files, these rules will also trigger for any file named <tt class="docutils literal">foo.rules</tt> or <tt class="docutils literal">bar.metadata</tt>. That seems a bit too broad for me, so I have opted out of that for now. The down side is that these files will not work out of the box with <tt class="docutils literal">kate</tt> for now.</p> <p>The current LSP configuration in <tt class="docutils literal">kate</tt> does not recognize makefiles or YAML either. Ideally, we would assign custom languages for the affected Debian files, so we do not steal the ID from other language servers. Notably, <tt class="docutils literal">kate</tt> has a built-in language server for YAML and <tt class="docutils literal">debputy</tt> does nothing for a generic YAML document. However, adding YAML as a supported language for <tt class="docutils literal">debputy</tt> would cause conflict and regressions for users that are already happy with their generic YAML language server from <tt class="docutils literal">kate</tt>.</p> <p>So there are certainly still work to be done. If you are good with <tt class="docutils literal">KSyntaxHighlighting</tt> and know how to solve some of this, I hope you will help me out.</p> </div> <div class="section" id="changes-unrelated-to-kate"> <h2>Changes unrelated to <tt class="docutils literal">kate</tt></h2> <p>While I was working on <tt class="docutils literal">debputy</tt>, I also added some other features that I want to mention.</p> <blockquote> <ol class="arabic"> <li><p class="first">The <tt class="docutils literal">debputy lint</tt> command will now show related context to diagnostic in its terminal report when such information is available and is from the same file as the diagnostic itself (cross file cases are rendered without related information).</p> <p>The related information is typically used to highlight a source of a conflict. As an example, if you use the same field twice in a stanza of <tt class="docutils literal">debian/control</tt>, then <tt class="docutils literal">debputy</tt> will add a diagnostic to the second occurrence. The related information for that diagnostic would provide the position of the first occurrence.</p> <p>This should make it easier to find the source of the conflict in the cases where <tt class="docutils literal">debputy</tt> provides it. Let me know if you are missing it for certain diagnostics.</p> </li> <li><p class="first">The diagnostics analysis of <tt class="docutils literal">debian/control</tt> will now identify and flag simple duplicated relations (complex ones like OR relations are ignored for now). Thanks to Matthias Geiger for suggesting the feature and Otto Kekäläinen for reporting a false positive that is now fixed.</p> </li> </ol> </blockquote> </div> <div class="section" id="closing"> <h2>Closing</h2> <p>I am glad I tested with <tt class="docutils literal">kate</tt> to weed out most of these issues in time before the freeze. The Debian freeze will start within a week from now. Since <tt class="docutils literal">debputy</tt> is a part of the toolchain packages it will be frozen from there except for important bug fixes.</p> </div> </div> <p class="date"> <a href="https://people.debian.org/~nthykier/blog/2025/improving-debian-packaging-in-kate.html">09 March, 2025 12:05PM</a> by Niels Thykier </p> </div> </div> </div> <h1>March 08, 2025</h1> <div class="channel"> <a href="https://gwolf.org"> <img class="face" src="heads/gwolf.png" width="69" height="83" alt="hackergotchi for Gunnar Wolf" /> </a> <h2 class="planet-title"> <a href="https://gwolf.org" title="Gunnar Wolf - Nice grey life">Gunnar Wolf</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://gwolf.org/2025/03/the-author-has-been-doctored.html_hide\" onClick=\"exclude( 'https://gwolf.org/2025/03/the-author-has-been-doctored.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://gwolf.org/2025/03/the-author-has-been-doctored.html_show\" style=\"display:none;\" onClick=\"show( 'https://gwolf.org/2025/03/the-author-has-been-doctored.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://gwolf.org/2025/03/the-author-has-been-doctored.html" class="https://gwolf.org/2025/03/the-author-has-been-doctored.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://gwolf.org/2025/03/the-author-has-been-doctored.html">The author has been doctored.</a> </h3> <div class="content"> <p>Almost exactly four years after I started with this project, yesterday I presented my PhD defense.</p> <p><a href="https://gwolf.org/files/2025-03/examen.800.jpg"> <img height="180" src="https://gwolf.org/files/2025-03/examen.400.jpg" width="400" /> </a></p> <p>My thesis was what I’ve been presenting advances of all around since ≈2022: <em>«A certificate-poisoning-resistant protocol for the synchronization of Web of Trust networks»</em></p> <p>Lots of paperwork is still on the road for me. But at least in the immediate future, I can finally use this keyring my friend Raúl Gómez 3D-printed for me:</p> <p><a href="https://gwolf.org/files/2025-03/dr.gwolf.jpg"> <img height="405" src="https://gwolf.org/files/2025-03/dr.gwolf.400.jpg" width="400" /> </a></p> </div> <p class="date"> <a href="https://gwolf.org/2025/03/the-author-has-been-doctored.html">08 March, 2025 06:31PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="https://debianbrasil.org.br/"> <img class="face" src="heads/debianbrasil.png" width="65" height="85" alt="hackergotchi for Debian Brasil" /> </a> <h2 class="planet-title"> <a href="https://debianbrasil.org.br/" title="Debian Brasil">Debian Brasil</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/_hide\" onClick=\"exclude( 'https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/_show\" style=\"display:none;\" onClick=\"show( 'https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/" class="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/"> <div class="entry"> <h3 class="entry-title"> <a href="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/">MiniDebConf Belo Horizonte 2024 - a brief report</a> </h3> <div class="content"> <p>From April 27th to 30th, 2024, <a href="https://bh.mini.debconf.org/">MiniDebConf Belo Horizonte 2024</a> was held at the Pampulha Campus of <a href="https://ufmg.br">UFMG - Federal University of Minas Gerais</a>, in Belo Horizonte city.</p> <p><img alt="MiniDebConf BH 2024 banners" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-banners.jpg" width="400" /> This was the fifth time that a MiniDebConf (as an exclusive in-person event about Debian) took place in Brazil. Previous editions were in Curitiba (<a href="https://br2016.mini.debconf.org/">2016</a>, <a href="https://br2017.mini.debconf.org">2017</a>, and <a href="https://br2018.mini.debconf.org">2018</a>), and in <a href="https://brasilia.mini.debconf.org">Brasília 2023</a>. We had other MiniDebConfs editions held within Free Software events such as <a href="http://fisl.org.br">FISL</a> and <a href="https://latinoware.org/">Latinoware</a>, and other online events. See our <a href="https://bh.mini.debconf.org/evento/edicoes-anteriores/">event history</a>.</p> <p>Parallel to MiniDebConf, on 27th (Saturday) <a href="https://flisol.info/FLISOL2024/Brasil">FLISOL - Latin American Free Software Installation Festival</a> took place. It's the largest event in Latin America to promote Free Software, and It has been held since 2005 simultaneously in several cities.</p> <p>MiniDebConf Belo Horizonte 2024 was a success (as were previous editions) thanks to the participation of everyone, regardless of their level of knowledge about Debian. We value the presence of both beginner users who are familiarizing themselves with the system and the official project developers. The spirit of welcome and collaboration was present during all the event.</p> <p><img alt="MiniDebConf BH 2024 flisol" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-flisol.jpg" width="400" /> </p> <h2>2024 edition numbers</h2> <p>During the four days of the event, several activities took place for all levels of users and collaborators of the Debian project. The official schedule was composed of:</p> <ul> <li>06 rooms in parallel on Saturday;</li> <li>02 auditoriums in parallel on Monday and Tuesday;</li> <li>30 talks/BoFs of all levels;</li> <li>05 workshops for hands-on activities;</li> <li>09 lightning talks on general topics;</li> <li>01 Live Electronics performance with Free Software;</li> <li>Install fest to install Debian on attendees' laptops;</li> <li>BSP (Bug Squashing Party);</li> <li>Uploads of new or updated packages.</li> </ul> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-palestra-1.jpg" width="400" /> The final numbers for MiniDebConf Belo Horizonte 2024 show that we had a record number of participants.</p> <ul> <li>Total people registered: 399</li> <li>Total attendees in the event: 224</li> </ul> <p>Of the 224 participants, 15 were official Brazilian contributors, 10 being DDs (Debian Developers) and 05 (Debian Maintainers), in addition to several unofficial contributors.</p> <p>The organization was carried out by 14 people who started working at the end of 2023, including Prof. Loïc Cerf from the Computing Department who made the event possible at UFMG, and 37 volunteers who helped during the event.</p> <p>As MiniDebConf was held at UFMG facilities, we had the help of more than 10 University employees.</p> <p>See the <a href="https://bh.mini.debconf.org/evento/organizadores/">list</a> with the names of people who helped in some way in organizing MiniDebConf Belo Horizonte 2024.</p> <p>The difference between the number of people registered and the number of attendees in the event is probably explained by the fact that there is no registration fee, so if the person decides not to go to the event, they will not suffer financial losses.</p> <p>The 2024 edition of MiniDebconf Belo Horizonte was truly grand and shows the result of the constant efforts made over the last few years to attract more contributors to the Debian community in Brazil. With each edition the numbers only increase, with more attendees, more activities, more rooms, and more sponsors/supporters.</p> <p><img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-grupo-1.jpg" width="400" /> <br /> <br /> <img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-grupo-2.jpg" width="400" /> </p> <h2>Activities</h2> <p>The MiniDebConf schedule was intense and diverse. On the 27th, 29th and 30th (Saturday, Monday and Tuesday) we had talks, discussions, workshops and many practical activities.</p> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-palestra-2.jpg" width="400" /> On the 28th (Sunday), the Day Trip took place, a day dedicated to sightseeing around the city. In the morning we left the hotel and went, on a chartered bus, to the <a href="https://mercadocentral.com.br/">Belo Horizonte Central Market</a>. People took the opportunity to buy various things such as cheeses, sweets, cachaças and souvenirs, as well as tasting some local foods.</p> <p><img alt="MiniDebConf BH 2024 mercado" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-mercado.jpg" width="400" /> After a 2-hour tour of the Market, we got back on the bus and hit the road for lunch at a typical Minas Gerais food restaurant.</p> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-restaurante.jpg" width="400" /> With everyone well fed, we returned to Belo Horizonte to visit the city's main tourist attraction: Lagoa da Pampulha and Capela São Francisco de Assis, better known as <a href="http://portalbelohorizonte.com.br/o-que-fazer/arte-e-cultura/igrejas/igreja-sao-francisco-de-assis">Igrejinha da Pampulha</a>. <img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-igrejinha.jpg" width="400" /> We went back to the hotel and the day ended in the hacker space that we set up in the events room for people to chat, packaging, and eat pizzas.</p> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-hotel.jpg" width="400" /> </p> <h2>Crowdfunding</h2> <p>For the third time we ran a crowdfunding campaign and it was incredible how people contributed! The initial goal was to raise the amount equivalent to a gold tier of R$ 3,000.00. When we reached this goal, we defined a new one, equivalent to one gold tier + one silver tier (R$ 5,000.00). And again we achieved this goal. So we proposed as a final goal the value of a gold + silver + bronze tiers, which would be equivalent to R$ 6,000.00. The result was that we raised R$7,239.65 (~ USD 1,400) with the help of more than 100 people!</p> <p>Thank you very much to the people who contributed any amount. As a thank you, we <a href="https://bh.mini.debconf.org/doacoes/">list the names of the people who donated</a>. <img alt="MiniDebConf BH 2024 doadores" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-doadores.jpg" width="400" /> </p> <h2>Food, accommodation and/or travel grants for participants</h2> <p>Each edition of MiniDebConf brought some innovation, or some different benefit for the attendees. In this year's edition in Belo Horizonte, as with DebConfs, we <a href="https://bh.mini.debconf.org/evento/bolsas/">offered bursaries for food, accommodation and/or travel</a> to help those people who would like to come to the event but who would need some kind of help.</p> <p>In the registration form, we included the option for the person to request a food, accommodation and/or travel bursary, but to do so, they would have to identify themselves as a contributor (official or unofficial) to Debian and write a justification for the request.</p> <p>Number of people benefited:</p> <ul> <li>Food: 69</li> <li>Accommodation: 20</li> <li>Travel: 18</li> </ul> <p>The food bursary provided lunch and dinner every day. The lunches included attendees who live in Belo Horizonte and the region. Dinners were paid for attendees who also received accommodation and/or travel. The accommodation was held at the <a href="https://www.bhjaraguahotel.com.br/">BH Jaraguá Hotel</a>. And the travels included airplane or bus tickets, or fuel (for those who came by car or motorbike).</p> <p>Much of the money to fund the bursaries came from the Debian Project, mainly for travels. We sent a budget request to the former Debian leader Jonathan Carter, and He promptly approved our request.</p> <p>In addition to this event budget, the leader also approved individual requests sent by some DDs who preferred to request directly from him.</p> <p>The experience of offering the bursaries was really good because it allowed several people to come from other cities.</p> <p><img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-jantar.jpg" width="400" /> </p> <h2>Photos and videos</h2> <p>You can watch recordings of the talks at the links below:</p> <ul> <li><a href="https://www.youtube.com/playlist?list=PLU90bw3OpxLpu7hJO8TzySFX32_UD8Eh4">Youtube</a> - <a href="https://peertube.debian.social/w/p/3X7BY1MyH686QNCS2A6wkd">Peertube</a></li> <li><p><a href="https://meetings-archive.debian.net/pub/debian-meetings/2024/MiniDebConf-Belo-Horizonte/">video.debian.net</a> And see the photos taken by several collaborators in the links below:</p></li> <li><p><a href="https://photos.app.goo.gl/ZV14bZ9AQFaKsgio6">Google photos</a></p></li> <li><a href="https://cloud.debianbsb.org/s/wgzBtzKX2kbLCYP">Nextcloud</a></li> </ul> <h2>Thanks</h2> <p>We would like to thank all the attendees, organizers, volunteers, sponsors and supporters who contributed to the success of MiniDebConf Belo Horizonte 2024.</p> <p><img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-ate-2025.jpg" width="400" /> </p> <h2>Sponsors</h2> <p><strong>Gold:</strong></p> <ul> <li><a href="https://www.collabora.com/">Collabora</a></li> </ul> <p><strong>Silver:</strong></p> <ul> <li><a href="https://jedai.ai/">Jedai.ai</a></li> <li><a href="https://www.toradex.com/pt-br">Toradex Brasil</a></li> <li><a href="https://www.globo.com">Globo.com</a></li> <li><a href="https://policorp.com.br">Policorp Tecnologia</a></li> </ul> <p><strong>Bronze:</strong></p> <ul> <li><a href="https://brdsoft.com.br/">BRDSoft - Tecnologias para TI e Telecomunicações</a></li> <li><p><a href="https://eita.coop.br/">EITA - Cooperativa de Trabalho Educação, Informação e Tecnologia para Autogestão</a> </p> <h2>Supporters</h2></li> <li><p><a href="https://ictl.org.br">ICTL - Instituto para Conservação de Tecnologias Livres</a> - <a href="https://www.nazinha.com.br/">Nazinha Alimentos</a></p></li> <li>DACOMPSI</li> </ul> <h2>Organizers</h2> <ul> <li><a href="https://www.debian.org/">Projeto Debian</a></li> <li><a href="https://debianbrasil.org.br/">Comunidade Debian Brasil</a></li> <li><a href="https://debian-minas-gerais.gitlab.io/site/">Comunidade Debian MG</a></li> <li><a href="https://dcc.ufmg.br/">DCC/UFMG - Departamento de Ciência da Computação da Universidade Federal de Minas Gerais</a> </li> </ul> </div> <p class="date"> <a href="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/">08 March, 2025 05:28PM</a> </p> </div> </div> </div> <div class="channel"> <a href="http://dirk.eddelbuettel.com/blog"> <img class="face" src="heads/dirk.png" width="65" height="90" alt="hackergotchi for Dirk Eddelbuettel" /> </a> <h2 class="planet-title"> <a href="http://dirk.eddelbuettel.com/blog" title="Thinking inside the box">Dirk Eddelbuettel</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3_hide\" onClick=\"exclude( 'http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3_show\" style=\"display:none;\" onClick=\"show( 'http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3" class="http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3"> <div class="entry"> <h3 class="entry-title"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3">RcppTOML 0.2.3 on CRAN: Compiler Nag, Small Updates</a> </h3> <div class="content"> <p>A new (mostly maintenance) release 0.2.3 of <a href="https://dirk.eddelbuettel.com/code/rcpp.toml.html">RcppTOML</a> is now on <a href="https://cran.r-project.org">CRAN</a>.</p> <p><a href="https://toml.io/en/">TOML</a>is a file format that is most suitable for configurations, as it is meant to be <em>edited by humans</em> but read by computers. It emphasizes <em>strong readability for humans</em> while at the same time supporting <em>strong typing</em> as well as <em>immediate and clear error reports</em>. On small typos you get parse errors, rather than silently corrupted garbage. Much preferable to any and all of XML, JSON or YAML – though sadly these may be too ubiquitous now. <a href="https://toml.io/en/">TOML</a> is frequently being used with the projects such as the <a href="https://gohugo.io/">Hugo</a> static blog compiler, or the <a href="https://crates.io/">Cargo</a> system of Crates (aka “packages”) for the <a href="https://www.rust-lang.org/en-US/">Rust language</a>.</p> <p>This release was tickled by another <a href="https://cran.r-project.org">CRAN</a> request: just like yesterday’s and the <a href="https://dirk.eddelbuettel.com/blog/2025/03/06#rcppdate_0.0.5">RcppDate release</a> two days ago, it responds to the esoteric ‘whitespace in literal operator’ depreceation warning. We alerted upstream too.</p> <p>The short summary of changes follows.</p> <blockquote> <h4 id="changes-in-version-0.2.3-2025-03-08">Changes in version 0.2.3 (2025-03-08)</h4> <ul> <li><p>Correct the minimum version of <span class="pkg">Rcpp</span> to 1.0.8 (Walter Somerville)</p></li> <li><p>The package now uses Authors@R as mandated by CRAN</p></li> <li><p>Updated 'whitespace in literal' issue upsetting clang++-20</p></li> <li><p>Continuous integration updates including simpler r-ci setup</p></li> </ul> </blockquote> <p>Courtesy of my <a href="https://dirk.eddelbuettel.com/cranberries/">CRANberries</a>, there is also a diffstat report for <a href="https://dirk.eddelbuettel.com/cranberries/2025/03/08#RcppTOML_0.2.3">this release</a>. For questions, suggestions, or issues please use the <a href="https://github.com/eddelbuettel/rcptoml/issues">issue tracker</a> at the <a href="https://github.com/eddelbuettel/rcpptoml">GitHub repo</a>.</p> <p style="font-size: 80%; font-style: italic;"> This post by <a href="https://dirk.eddelbuettel.com">Dirk Eddelbuettel</a> originated on his <a href="https://dirk.eddelbuettel.com/blog/">Thinking inside the box</a> blog. If you like this or other open-source work I do, you can now <a href="https://github.com/sponsors/eddelbuettel">sponsor me at GitHub</a>. </p><p></p> </div> <p class="date"> <a href="http://dirk.eddelbuettel.com/blog/2025/03/08#rcpptoml_0.2.3">08 March, 2025 02:08PM</a> </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="https://vincent.bernat.ch/en" title="Vincent Bernat">Vincent Bernat</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases_hide\" onClick=\"exclude( 'https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases_show\" style=\"display:none;\" onClick=\"show( 'https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases" class="https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases"> <div class="entry"> <h3 class="entry-title"> <a href="https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases">Auto-expanding aliases in Zsh</a> </h3> <div class="content"> <p>To avoid needless typing, the <a href="https://fishshell.com/" title="fish shell: finally, a command line shell for the 90s">fish shell</a> features command abbreviations to expand some words after pressing space. We can emulate such a feature with <a href="https://www.zsh.org/" title="Zsh website">Zsh</a>:</p> <div class="language-bash codehilite"><pre><span></span><span class="c1"># Definition of abbrev-alias for auto-expanding aliases</span> <span class="nb">typeset</span><span class="w"> </span>-ga<span class="w"> </span>_vbe_abbrevations abbrev-alias<span class="o">()</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span><span class="nb">alias</span><span class="w"> </span><span class="nv">$1</span> <span class="w"> </span><span class="nv">_vbe_abbrevations</span><span class="o">+=(</span><span class="si">${</span><span class="nv">1</span><span class="p">%%</span><span class="se">\=</span><span class="p">*</span><span class="si">}</span><span class="o">)</span> <span class="o">}</span> _vbe_zle-autoexpand<span class="o">()</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span><span class="nb">local</span><span class="w"> </span>-a<span class="w"> </span>words<span class="p">;</span><span class="w"> </span><span class="nv">words</span><span class="o">=(</span><span class="si">${</span><span class="p">(z)LBUFFER</span><span class="si">}</span><span class="o">)</span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">((</span><span class="w"> </span><span class="si">${</span><span class="p">#_vbe_abbrevations[(r)</span><span class="si">${</span><span class="nv">words</span><span class="p">[-1]</span><span class="si">}</span><span class="p">]</span><span class="si">}</span><span class="w"> </span><span class="o">))</span><span class="p">;</span><span class="w"> </span><span class="k">then</span> <span class="w"> </span>zle<span class="w"> </span>_expand_alias <span class="w"> </span><span class="k">fi</span> <span class="w"> </span>zle<span class="w"> </span>magic-space <span class="o">}</span> zle<span class="w"> </span>-N<span class="w"> </span>_vbe_zle-autoexpand bindkey<span class="w"> </span>-M<span class="w"> </span>emacs<span class="w"> </span><span class="s2">" "</span><span class="w"> </span>_vbe_zle-autoexpand bindkey<span class="w"> </span>-M<span class="w"> </span>isearch<span class="w"> </span><span class="s2">" "</span><span class="w"> </span>magic-space <span class="c1"># Correct common typos</span> <span class="o">((</span><span class="w"> </span>$+commands<span class="o">[</span>git<span class="o">]</span><span class="w"> </span><span class="o">))</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">gti</span><span class="o">=</span>git <span class="o">((</span><span class="w"> </span>$+commands<span class="o">[</span>grep<span class="o">]</span><span class="w"> </span><span class="o">))</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">grpe</span><span class="o">=</span>grep <span class="o">((</span><span class="w"> </span>$+commands<span class="o">[</span>sudo<span class="o">]</span><span class="w"> </span><span class="o">))</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">suod</span><span class="o">=</span>sudo <span class="o">((</span><span class="w"> </span>$+commands<span class="o">[</span>ssh<span class="o">]</span><span class="w"> </span><span class="o">))</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">shs</span><span class="o">=</span>ssh <span class="c1"># Save a few keystrokes</span> <span class="o">((</span><span class="w"> </span>$+commands<span class="o">[</span>git<span class="o">]</span><span class="w"> </span><span class="o">))</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">gls</span><span class="o">=</span><span class="s2">"git ls-files"</span> <span class="o">((</span><span class="w"> </span>$+commands<span class="o">[</span>ip<span class="o">]</span><span class="w"> </span><span class="o">))</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">ip6</span><span class="o">=</span><span class="s1">'ip -6'</span> <span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">ipb</span><span class="o">=</span><span class="s1">'ip -brief'</span> <span class="o">}</span> <span class="c1"># Hard to remember options</span> <span class="o">((</span><span class="w"> </span>$+commands<span class="o">[</span>mtr<span class="o">]</span><span class="w"> </span><span class="o">))</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>abbrev-alias<span class="w"> </span><span class="nv">mtrr</span><span class="o">=</span><span class="s1">'mtr -wzbe'</span> </pre></div> <p>Here is a demo where <code>gls</code> is expanded to <code>git ls-files</code> after pressing space:</p> <figure><div class="lf-media-outer"><span class="lf-media-inner"><video class="lf-media lf-opaque" controls="" height="474" loop="" src="https://d2pzklc15kok91.cloudfront.net/images/zsh-autoexpand.d77548f9890738.mp4" width="544"></video></span></div>Auto-expanding <code>gls</code> to <code>git ls-files</code></figure> <p>I don’t auto-expand all aliases. I keep using regular aliases when slightly modifying the behavior of a command or for well-known abbreviations:</p> <div class="language-bash codehilite"><pre><span></span><span class="nb">alias</span><span class="w"> </span><span class="nv">df</span><span class="o">=</span><span class="s1">'df -h'</span> <span class="nb">alias</span><span class="w"> </span><span class="nv">du</span><span class="o">=</span><span class="s1">'du -h'</span> <span class="nb">alias</span><span class="w"> </span><span class="nv">rm</span><span class="o">=</span><span class="s1">'rm -i'</span> <span class="nb">alias</span><span class="w"> </span><span class="nv">mv</span><span class="o">=</span><span class="s1">'mv -i'</span> <span class="nb">alias</span><span class="w"> </span><span class="nv">ll</span><span class="o">=</span><span class="s1">'ls -ltrhA'</span> </pre></div> </div> <p class="date"> <a href="https://vincent.bernat.ch/en/blog/2025-zsh-autoexpand-aliases">08 March, 2025 09:58AM</a> by Vincent Bernat </p> </div> </div> </div> <h1>March 07, 2025</h1> <div class="channel"> <a href="http://phls.com.br"> <img class="face" src="heads/phls.png" width="65" height="85" alt="hackergotchi for Paulo Henrique de Lima Santana" /> </a> <h2 class="planet-title"> <a href="http://phls.com.br" title="Blog de Paulo Santana - Debian">Paulo Henrique de Lima Santana</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://phls.com.br/bits-from-fosdem-2025_hide\" onClick=\"exclude( 'http://phls.com.br/bits-from-fosdem-2025' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://phls.com.br/bits-from-fosdem-2025_show\" style=\"display:none;\" onClick=\"show( 'http://phls.com.br/bits-from-fosdem-2025' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://phls.com.br/bits-from-fosdem-2025" class="http://phls.com.br/bits-from-fosdem-2025"> <div class="entry"> <h3 class="entry-title"> <a href="http://phls.com.br/bits-from-fosdem-2025">Bits from FOSDEM 2025</a> </h3> <div class="content"> <p>This year I was at <a href="https://fosdem.org/2025/">FOSDEM 2025</a>, and it was the fifth edition in a row that I participated in person (before it was in 2019, <a href="https://phls.com.br/bits-from-minidebcamp-brussels-and-fosdem-2020">2020</a>, <a href="https://phls.com.br/bits-from-fosdem-2023-and-2024">2023 and 2024</a>). The event took place on February 1st and 2nd, as always at the ULB campus in Brussels.</p> <p>We arrived on Friday at lunchtime and went straight to the hotel to drop off our bags. This time we stayed at Ibis in the city center, very close to the hustle and bustle. The price was good and the location was really good for us to be able to go out in the city center and come back late at night. We found a Japanese restaurant near the hotel and it was definitely worth having lunch there because of the all-you-can-eat price. After taking a nap, we went out for a walk. Since January 31st is the last day of the winter sales in the city, the streets in the city center were crowded, there were lots of people in the stores, and the prices were discounted. We concluded that if we have the opportunity to go to Brussels again at this time, it would be better wait to buy clothes for cold weather there.</p> <p><br /> <img alt="Fosdem 2025" src="https://phls.com.br/assets/img/fosdem-2025-03.jpg" /> <br /></p> <p>Unlike in 2023 and 2024, the FOSDEM organization did not approve my request for the <a href="https://fosdem.org/2024/schedule/track/translations/">Translations DevRoom</a>,so my goal was to participate in the event and collaborate at the Debian booth. And also as I always do, I volunteered to operate the broadcast camera in the main auditorium on both days, for two hours each.</p> <p>The Debian booth: <br /> <img alt="Fosdem 2025" src="https://phls.com.br/assets/img/fosdem-2025-04.jpg" /> <br /></p> <p>Me in the auditorium helping with the broadcast: <br /> <img alt="Fosdem 2025" src="https://phls.com.br/assets/img/fosdem-2025-01.jpg" /> <br /></p> <p>2 weeks before the event, the organization <a href="https://fosdem.org/2025/news/2025-01-18-bof-rooms/">put out a call</a> for interested people to request a room for their community’s BoF (Birds of a Feather), and I requested a room for Debian and <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6744-debian-bof/">it was approved</a> :-)</p> <p>It was great to see that people were really interested in participating at the BoF and the room was packed! As the host of the discussions, I tried to leave the space open for anyone who wanted to talk about any subject related to Debian. We started with a talk from <a href="https://debconf25.debconf.org/">MiniDebConf25</a> organizers, that will be taking place this year in France. Then other topics followed with people talking, asking and answering questions, etc. It was worth organizing this BoF. Who knows, the idea will remain in 2026.</p> <p><br /> <img alt="Fosdem 2025" src="https://phls.com.br/assets/img/fosdem-2025-05.jpg" /> <br /></p> <p><a href="https://fosdem.org/2025/schedule/speaker/carlos_henrique_lima_melara/">Carlos (a.k.a Charles)</a>, <a href="https://fosdem.org/2025/schedule/speaker/athos_ribeiro/">Athos</a>, <a href="https://fosdem.org/2025/schedule/speaker/maira_canal/">Maíra</a> and <a href="https://fosdem.org/2025/schedule/speaker/melissa_wen/">Melissa</a> talked at Fosdem, and Kanashiro was one for organizers of <a href="https://fosdem.org/2025/schedule/track/distributions/.">Distributions DevRoom</a></p> <p><br /> <img alt="Fosdem 2025" src="https://phls.com.br/assets/img/fosdem-2025-02.jpg" /> <br /></p> <p>During the two days of the event, it didn’t rain or get too cold. The days were sunny (and people celebrated the weather in Brussels). But I have to admit that it would have been nice to see snow like I did in 2019. Unlike last year, this time I felt more motivated to stay at the event the whole time.</p> <p>Deixo meu agradecimento especial para o Andreas Tille, atual Líder do Debian que aprovou o meu pedido de passagens para que eu pudesse participar dos FOSDEM 2025. Como sempre, essa ajuda foi essencial para viabilizar a minha viagem para Bruxelas.</p> <p>I would like to give my special thanks to Andreas Tille, the current Debian Leader, who approved my request for flight tickets so that I could join FOSDEM 2025. As always, this help was essential in making my trip to Brussels possible.</p> <p>And once again Jandira was with me on this adventure. On Monday we went for a walk around Brussels and we also traveled to visit Bruges again. The visit to this city is really worth it because walking through the historic streets is like going back in time. This time we even took a boat trip through the canals, which was really cool.</p> <p><br /> <img alt="Fosdem 2025" src="https://phls.com.br/assets/img/fosdem-2025-07.jpg" /> <br /> <br /> <img alt="Fosdem 2025" src="https://phls.com.br/assets/img/fosdem-2025-06.jpg" /></p> </div> <p class="date"> <a href="http://phls.com.br/bits-from-fosdem-2025">07 March, 2025 02:00PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="http://bonedaddy.net/pabs3/log/" title="Log">Paul Wise</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/_hide\" onClick=\"exclude( 'http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/_show\" style=\"display:none;\" onClick=\"show( 'http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/" class="http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/"> <div class="entry"> <h3 class="entry-title"> <a href="http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/">FLOSS Activities February 2025</a> </h3> <div class="content"> <h1 id="focus">Focus</h1> <p>This month I didn't have any particular focus. I just worked on issues in my info bubble.</p> <h1 id="changes">Changes</h1> <ul> <li>swh-web: <a href="https://gitlab.softwareheritage.org/swh/devel/swh-web/-/merge_requests/1393">block empty GitLab instances for Add Forge Now</a></li> <li>Debian wiki pages: <a href="https://wiki.debian.org/Exploits?action=diff&rev1=40&rev2=41">Exploits</a>, <a href="https://wiki.debian.org/SocialEventAndConferenceCalendars?action=diff&rev1=26&rev2=27">SocialEventAndConferenceCalendars</a></li> </ul> <h1 id="issues">Issues</h1> <ul> <li>Crashes in <a href="https://github.com/jwilk/zygolophodon/issues/9">zygolophodon</a></li> <li>Features in <a href="https://github.com/saveweb/wikiteam3/issues/40">wikiteam3</a></li> <li>Warnings in <a href="https://bugs.debian.org/1095195">local-apt-repository</a>, <a href="https://bugs.debian.org/1098785">libselinux1</a></li> </ul> <h1 id="sponsors">Sponsors</h1> <p>The SWH work was sponsored. All other work was done on a volunteer basis.</p> </div> <p class="date"> <a href="http://bonedaddy.net/pabs3/log/2025/03/07/floss-activities/">07 March, 2025 07:26AM</a> </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="https://blog.trueelena.org" title="Valhalla's things">Valhalla's Things</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html_hide\" onClick=\"exclude( 'https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html_show\" style=\"display:none;\" onClick=\"show( 'https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html" class="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html">MOAR Slippers</a> </h3> <div class="content"> <article> <section class="header"> Posted on March 7, 2025 <br /> Tags: <a href="https://blog.trueelena.org/tags/madeof%3Aatoms.html" title="All pages tagged 'madeof:atoms'.">madeof:atoms</a>, <a href="https://blog.trueelena.org/tags/craft%3Asewing.html" title="All pages tagged 'craft:sewing'.">craft:sewing</a>, <a href="https://blog.trueelena.org/tags/FreeSoftWear.html" title="All pages tagged 'FreeSoftWear'.">FreeSoftWear</a> </section> <section> <p><img alt="A pair of espadrille-style slippers in black denim with a shiny black design on the uppers and twine soles." class="align-center" src="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/black_denim_slippers.jpg" style="width: 80.0%;" /></p> <p>A couple of years ago, I <a href="https://blog.trueelena.org/blog/2023/05/04-linen_slippers/index.html">made myself a pair of slippers in linen with a braided twine sole</a> and then <a href="https://blog.trueelena.org/blog/2023/05/05-hiking_slippers/index.html">another pair of hiking slippers</a>: I am happy to report that they have been mostly a success.</p> <p>Now, as I feared, the white linen fabric wasn’t a great choice: not only it became dirt-grey linen fabric in a very short time, the area under the ball of the foot was quickly consumed by friction, just as it usually happens with bought slippers.</p> <p>I have no pictures for a number of reasons, but trust me when I say that they look pretty bad.</p> <p><img alt="The same slippers, one of them is turned upside down to show the sole made from a twine braid, sewn in a spiral until it is the shape of a sole." class="align-center" src="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/black_denim_slipper_and_sole.jpg" style="width: 80.0%;" /></p> <p>However, the sole is still going strong, and the general concept has proved valid, so when I needed a second pair of slippers I used <a href="https://sewing-patterns.trueelena.org/contemporary_unisex/accessories/slippers/index.html">the same pattern</a>, with <a href="https://fiber-patterns.trueelena.org/feet/braided_twine_soles/index.html">a sole made from the same twine</a> but this time with denim taken from the legs of an old pair of jeans.</p> <p>To make them a bit nicer, and to test the technique, I also added a design with a stencil and iridescent black acrylic paint (with fabric medium): I like the tone-on-tone effect, as it’s both (relatively) subtle and shiny.</p> <p><img alt="A pair of open-heeled slippers in faded blue jeans." class="align-center" src="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/open_heeled_slippers.jpg" style="width: 80.0%;" /></p> <p>Then, my partner also needed new slippers, and I wanted to make his too.</p> <p>His preference, however, is for open heeled slippers, so I adjusted the pattern into <a href="https://sewing-patterns.trueelena.org/contemporary_unisex/accessories/open_heeled_slippers/index.html">a new one</a>, making it from an old pair of blue jeans, rather than black as mine.</p> <p><img alt="A braided twine sole, showing how an heel has been made in the same technique and sewn under the sole with blanket stitches." class="align-center" src="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/sole_with_heel_side.jpg" style="width: 80.0%;" /></p> <p>He also finds completely flat soles a bit uncomfortable, so I made an heel with the same braided twine technique: this also seems to be working fine, and I’ve also added <a href="https://fiber-patterns.trueelena.org/feet/braided_twine_soles/index.html#optional-heel">these instructions to the braided soles ones</a></p> <p>Both of these have now been work for a few months: the jeans is working much better than the linen (which isn’t a complete surprise) and we’re both finding them comfortable, so if we’ll ever need new slippers I think I’ll keep using this pattern.</p> <p>Now the plan is to wash the linen slippers, and then look into repairing them, either with just a new fabric inner sole + padding, or if washing isn’t as successful as I’d like by making a new fabric part in a different material and reusing just the twine sole. Either way they are going back into use.</p> </section> </article> </div> <p class="date"> <a href="https://blog.trueelena.org/blog/2025/03/07-moar_slippers/index.html">07 March, 2025 12:00AM</a> </p> </div> </div> </div> <h1>March 06, 2025</h1> <div class="channel"> <h2 class="planet-title"> <a href="https://anarc.at/tag/debian-planet/" title="pages tagged debian-planet">Antoine Beaupré</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://anarc.at/blog/2025-03-06-nix/_hide\" onClick=\"exclude( 'https://anarc.at/blog/2025-03-06-nix/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://anarc.at/blog/2025-03-06-nix/_show\" style=\"display:none;\" onClick=\"show( 'https://anarc.at/blog/2025-03-06-nix/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://anarc.at/blog/2025-03-06-nix/" class="https://anarc.at/blog/2025-03-06-nix/"> <div class="entry"> <h3 class="entry-title"> <a href="https://anarc.at/blog/2025-03-06-nix/">Nix Notes</a> </h3> <div class="content"> <h1 id="meta">Meta</h1> <p>In case you haven't noticed, I'm trying to post and one of the things that entails is to just dump over the fence a bunch of draft notes. In this specific case, I had a set of rough notes about <a href="https://en.wikipedia.org/wiki/NixOS">NixOS</a> and particularly <a href="https://en.wikipedia.org/wiki/Nix_(package_manager)">Nix, the package manager</a>.</p> <p>In this case, you can see the very birth of an article, what it looks like before it becomes the questionable prose it is now, by looking at the <a href="https://gitlab.com/anarcat/anarc.at/-/blob/main/blog/2025-03-06-nix.md?ref_type=heads">Git history of this file</a>, particularly its <a href="https://gitlab.com/anarcat/anarc.at/-/blob/83ff51e4f06764a464b85664146e8fefedd08efe/blog/2025-03-06-nix.md">birth</a>. I have a couple of those left, and it would be pretty easy to publish them as is, but I feel I'd be doing others (and myself! I write for my own documentation too after all) a disservice by not going the extra mile on those.</p> <p>So here's the long version of my experiment with Nix.</p> <h1 id="nix">Nix</h1> <p>A couple friends are real fans of Nix. Just like I <a href="https://gitlab.torproject.org/tpo/tpa/team/-/wikis/howto/puppet">work with Puppet a lot</a>, they deploy and maintain servers (if not fleets of servers) with NixOS and its declarative package management system. Essentially, they use it as a configuration management system, which is pretty awesome.</p> <p>That, however, is a bit too high of a bar for me. I rarely try new operating systems these days: I'm a Debian developer and it takes most of my time to keep that functional. I'm not going to go around messing with other systems as I know that would inevitably get me dragged down into contributing into yet another free software project. I'm mature now and know where to draw the line. Right?</p> <p>So I'm just testing Nix, the package manager, on Debian, because I learned from my friend that <a href="https://github.com/nixos/nixpkgs">nixpkgs</a> is the <a href="https://repology.org/repositories/statistics/total">largest package repository</a> out there, a mind-boggling 100,000 at the time of writing (with <a href="https://repology.org/repositories/statistics/pnewest">88% of packages up to date</a>), compared to around 40,000 in Debian (or 72,000 if you count binary packages, with 72% up to date). I naively thought Debian was the largest, perhaps competing with Arch, and I was wrong: Arch is larger than Debian too.</p> <p>What brought me there is I wanted to run <a href="https://writewithharper.com/">Harper</a>, a fast spell-checker written in Rust. The logic behind using Nix instead of just downloading the source and running it myself is that I delegate the work of supply-chain integrity checking to a distributor, a bit like you trust Debian developers like myself to package things in a sane way. I know this widens the attack surface to a third party of course, but the rationale is that I shift cryptographic verification to another stack than just "TLS + GitHub" (although that is somewhat still involved) that's <em>linked</em> with my current chain (Debian packages).</p> <p>I have since then <a href="https://gitlab.com/anarcat/emacs-d/-/commit/093318283240b428b6ff2b8fdd565a82161ae03a">stopped using Harper for various reasons</a> and also wrapped up my Nix experiment, but felt it worthwhile to jot down some observations on the project.</p> <h1 id="hot-take">Hot take</h1> <p>Overall, Nix is hard to get into, with a complicated learning curve. I have found the documentation to be a bit confusing, since there are many ways to do certain things. I particularly tripped on "flakes" and, frankly, incomprehensible error reporting.</p> <p>It didn't help that I tried to run nixpkgs on Debian which is technically possible, but you can tell that I'm not supposed to be doing this. My friend who reviewed this article expressed surprised at how easy this was, but then he only saw the finished result, not me tearing my hair out to make this actually work.</p> <h1 id="nix-on-debian-primer">Nix on Debian primer</h1> <p>So here's how I got started. First I installed the <a href="https://tracker.debian.org/pkg/nix">nix binary package</a>:</p> <pre><code>apt install nix-bin </code></pre> <p>Then I had to add myself to the right group and logout/log back in to get the rights to deploy Nix packages:</p> <pre><code>adduser anarcat nix-users </code></pre> <p>That wasn't easy to find, but is mentioned in the <a href="https://sources.debian.org/src/nix/2.24.12%2Bdfsg-1/debian/nix-bin.README.Debian/">README.Debian file</a> shipped with the Debian package.</p> <p>Then, I didn't write this down, but the <code>README.Debian</code> file above mentions it, so I <em>think</em> I added a "channel" like this:</p> <pre><code>nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs nix-channel --update </code></pre> <p>And I likely installed the <a href="https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ha/harper/package.nix">Harper package</a> with:</p> <pre><code>nix-env --install harper </code></pre> <p>At this point, <code>harper</code> was installed in a ... profile? Not sure.</p> <p>I had to add <code>~/.nix-profile/bin</code> (a symlink to <code>/nix/store/sympqw0zyybxqzz6fzhv03lyivqqrq92-harper-0.10.0/bin</code>) to my <code>$PATH</code> environment for this to actually work.</p> <h2 id="side-notes-on-documentation">Side notes on documentation</h2> <p>Those last two commands (<code>nix-channel</code> and <code>nix-env</code>) were hard to figure out, which is kind of amazing because you'd think a tutorial on Nix would feature something like this prominently. But <a href="https://zero-to-nix.com/start/install/">three</a> <a href="https://nix.dev/manual/nix/2.24/quick-start">different</a> <a href="https://nix.dev/tutorials/">tutorials</a> failed to bring me up to that basic setup, even the <code>README.Debian</code> didn't spell that out clearly.</p> <p>The tutorials all show me how to <em>develop</em> packages for Nix, not plainly how to <em>install</em> Nix software. This is presumably because "I'm doing it wrong": you shouldn't just "install a package", you should setup an environment declaratively and tell it what you want to do.</p> <p>But here's the thing: I didn't <em>want</em> to "do the right thing". I just wanted to install Harper, and documentation failed to bring me to that basic "hello world" stage. Here's what one of the tutorials suggests as a first step, for example:</p> <pre><code>curl -L https://nixos.org/nix/install | sh nix-shell --packages cowsay lolcat nix-collect-garbage </code></pre> <p>... which, when you follow through, leaves you with almost precisely nothing left installed (apart from Nix itself, setup with a nasty "curl pipe bash". So while that works in testing Nix, you're not much better off than when you started.</p> <h2 id="rolling-back-everything">Rolling back everything</h2> <p>Now that I have stopped using Harper, I don't need Nix anymore, which I'm sure my Nix friends will be sad to read about. Don't worry, I have notes now, and can try again!</p> <p>But still, I wanted to clear things out, so I did this, as root:</p> <pre><code>deluser anarcat nix-users apt purge nix-bin rm -rf /nix ~/.nix* </code></pre> <p>I <em>think</em> this cleared things out, but I'm not actually sure.</p> <h1 id="side-note-on-nix-drama">Side note on Nix drama</h1> <p>This blurb wouldn't be complete without a mention that the Nix community has been somewhat tainted by the behavior of its founder. I won't bother you too much with this; <a href="https://lwn.net/Articles/970824/">LWN covered it well in 2024</a>, and made a <a href="https://lwn.net/Articles/981124/">followup article about spinoffs and forks</a> that's worth reading as well.</p> <p>I did want to say that everyone I have been in contact with in the Nix community was absolutely fantastic. So I am really sad that the behavior of a single individual can pollute a community in such a way.</p> <p>As a leader, if you have all but one responsability, it's to behave properly for people around you. It's actually really, really hard to do that, because yes, it means you need to act differently than others and no, you just don't get to be upset at others like you would normally do with friends, because you're in a position of authority.</p> <p>It's a lesson I'm still learning myself, to be fair. But at least I don't work with arms manufacturers or, if I would, I would be sure as hell to accept the nick (or nix?) on the chin when people would get upset, and try to make amends.</p> <p>So long live the Nix people! I hope the community recovers from that dark moment, so far it seems like it will.</p> <p>And thanks for helping me test Harper!</p> </div> <p class="date"> <a href="https://anarc.at/blog/2025-03-06-nix/">06 March, 2025 08:44PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="https://etbe.coker.com.au" title="etbe – Russell Coker">Russell Coker</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://etbe.coker.com.au/2025/03/06/8k-video-cards/_hide\" onClick=\"exclude( 'https://etbe.coker.com.au/2025/03/06/8k-video-cards/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://etbe.coker.com.au/2025/03/06/8k-video-cards/_show\" style=\"display:none;\" onClick=\"show( 'https://etbe.coker.com.au/2025/03/06/8k-video-cards/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://etbe.coker.com.au/2025/03/06/8k-video-cards/" class="https://etbe.coker.com.au/2025/03/06/8k-video-cards/"> <div class="entry"> <h3 class="entry-title"> <a href="https://etbe.coker.com.au/2025/03/06/8k-video-cards/">8k Video Cards</a> </h3> <div class="content"> <p>I previously blogged about <a href="https://etbe.coker.com.au/2024/12/15/hisense-65u80g-8k-tv/">getting an 8K TV [1]</a>. Now I’m working on getting 8K video out for a computer that talks to it. I borrowed an <a href="https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/rtx-a2000/nvidia-rtx-a2000-datasheet.pdf">NVidia RTX A2000 card which according to it’s specs can do 8K [2]</a> with a mini-DisplayPort to HDMI cable rated at 8K but on both Windows and Linux the two highest resolutions on offer are 3840*2160 (regular 4K) and 4096*2160 which is strange and not useful.</p> <p>The various documents on the A2000 differ on whether it has DisplayPort version 1.4 or 1.4a. According to the <a href="https://en.wikipedia.org/wiki/DisplayPort">DisplayPort Wikipedia page [3]</a> both versions 1.4 and 1.4a have a maximum of HBR3 speed and the difference is what version of DSC (<a href="https://en.wikipedia.org/wiki/Display_Stream_Compression">Display Stream Compression [4]</a>) is in use. DSC apparently causes no noticeable loss of quality for movies or games but apparently can be bad for text. According to the DisplayPort Wikipedia page version 1.4 can do 8K uncompressed at 30Hz or 24Hz with high dynamic range. So this should be able to work.</p> <p>My theories as to why it doesn’t work are:</p> <ul> <li>NVidia specs lie</li> <li>My 8K cable isn’t really an 8K cable</li> <li>Something weird happens converting DisplayPort to HDMI</li> <li>The video card can only handle refresh rates for 8K that don’t match supported input for the TV</li> </ul> <p>To get some more input on this issue I posted on Lemmy, <a href="https://lemmy.ml/post/26711723">here is the Lemmy post [5]</a>. I signed up to lemmy.ml because it was the first one I found that seemed reasonable and was giving away free accounts, I haven’t tried any others and can’t review it but it seems to work well enough and it’s free. It’s described as “A community of privacy and FOSS enthusiasts, run by Lemmy’s developers” which is positive, I recommend that everyone who’s into FOSS create an account there or some other Lemmy server.</p> <p>My Lemmy post was about what video cards to buy. I was looking at the Gigabyte RX 6400 Eagle 4G as a cheap card from a local store that does 8K, it also does DisplayPort 1.4 so might have the same issues, also apparently FOSS drivers don’t support 8K on HDMI because the people who manage HDMI specs are jerks. It’s a $200 card at MSY and a bit less on ebay so it’s an amount I can afford to risk on a product that might not do what I want, but it seems to have a high probability of getting the same result. The NVidia cards have the option of proprietary drivers which allow using HDMI and there are cards with DisplayPort 1.4 (which can do 8K@30Hz) and HDMI 2.1 (which can do 8K@50Hz). So HDMI is a better option for some cards just based on card output and has the additional benefit of not needing DisplayPort to HDMI conversion.</p> <p>The best option apparently is the Intel cards which do DisplayPort internally and convert to HDMI in hardware which avoids the issue of FOSS drivers for HDMI at 8K. The <a href="https://www.techpowerup.com/gpu-specs/arc-b580.c4244">Intel Arc B580 has nice specs [6]</a>, HDMI 2.1a and DisplayPort 2.1 output, 12G of RAM, and being faster than the low end cards like the RX 6400. But the local computer store price is $470 and the ebay price is a bit over $400. If it turns out to not do what I need it still will be a long way from the worst way I’ve wasted money on computer gear. But I’m still hesitating about this.</p> <p>Any suggestions?</p> <ul> <li>[1]<a href="https://etbe.coker.com.au/2024/12/15/hisense-65u80g-8k-tv/"> https://etbe.coker.com.au/2024/12/15/hisense-65u80g-8k-tv/</a></li> <li>[2]<a href="https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/rtx-a2000/nvidia-rtx-a2000-datasheet.pdf"> https://tinyurl.com/2cr32835</a></li> <li>[3]<a href="https://en.wikipedia.org/wiki/DisplayPort"> https://en.wikipedia.org/wiki/DisplayPort</a></li> <li>[4]<a href="https://en.wikipedia.org/wiki/Display_Stream_Compression"> https://en.wikipedia.org/wiki/Display_Stream_Compression</a></li> <li>[5]<a href="https://lemmy.ml/post/26711723"> https://lemmy.ml/post/26711723</a></li> <li>[6]<a href="https://www.techpowerup.com/gpu-specs/arc-b580.c4244"> https://www.techpowerup.com/gpu-specs/arc-b580.c4244</a></li> </ul> <div class="yarpp yarpp-related yarpp-related-rss yarpp-template-list"> <p>Related posts:</p><ol> <li><a href="https://etbe.coker.com.au/2020/02/16/displayport-4k/" rel="bookmark" title="DisplayPort and 4K">DisplayPort and 4K</a> <small>The Problem Video playback looks better with a higher scan...</small></li> <li><a href="https://etbe.coker.com.au/2020/10/19/video-decoding/" rel="bookmark" title="Video Decoding">Video Decoding</a> <small>I’ve had a saga of getting 4K monitors to work...</small></li> <li><a href="https://etbe.coker.com.au/2024/12/15/hisense-65u80g-8k-tv/" rel="bookmark" title="Hisense 65U80G 65″ Inch 8K ULED Android TV (2021)">Hisense 65U80G 65″ Inch 8K ULED Android TV (2021)</a> <small>The Aim I just bought a Hisense 65U80G 65″ Inch...</small></li> </ol> </div> </div> <p class="date"> <a href="https://etbe.coker.com.au/2025/03/06/8k-video-cards/">06 March, 2025 10:53AM</a> by etbe </p> </div> </div> </div> <h1>March 05, 2025</h1> <div class="channel"> <h2 class="planet-title"> <a href="https://reproducible-builds.org/blog/" title="reproducible-builds.org">Reproducible Builds</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://reproducible-builds.org/reports/2025-02/_hide\" onClick=\"exclude( 'https://reproducible-builds.org/reports/2025-02/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://reproducible-builds.org/reports/2025-02/_show\" style=\"display:none;\" onClick=\"show( 'https://reproducible-builds.org/reports/2025-02/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://reproducible-builds.org/reports/2025-02/" class="https://reproducible-builds.org/reports/2025-02/"> <div class="entry"> <h3 class="entry-title"> <a href="https://reproducible-builds.org/reports/2025-02/">Reproducible Builds in February 2025</a> </h3> <div class="content"> <p><a href="https://reproducible-builds.org/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/reproducible-builds.png#right" /></a></p> <p><strong>Welcome to the second report in 2025 from the <a href="https://reproducible-builds.org/">Reproducible Builds</a> project.</strong> Our monthly reports outline what we’ve been up to over the past month, and highlight items of news from elsewhere in the increasingly-important area of software supply-chain security. As usual, however, if you are interested in contributing to the Reproducible Builds project, please visit our <a href="https://reproducible-builds.org/contribute/"><em>Contribute</em></a> page on our website.</p> <p><strong>Table of contents:</strong></p> <ol> <li><a href="https://reproducible-builds.org/blog/index.rss#reproducible-builds-at-fosdem-2025">Reproducible Builds at FOSDEM 2025</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#reproducible-builds-at-pycascades-2025">Reproducible Builds at PyCascades 2025</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#does-functional-package-management-enable-reproducible-builds-at-scale">Does Functional Package Management Enable Reproducible Builds at Scale?</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#reproducedebiannet-updates"><em>reproduce.debian.net</em> updates</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#upstream-patches">Upstream patches</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#distribution-work">Distribution work</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#diffoscope--strip-nondeterminism">diffoscope & strip-nondeterminism</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#website-updates">Website updates</a></li> <li><a href="https://reproducible-builds.org/blog/index.rss#reproducibility-testing-framework">Reproducibility testing framework</a></li> </ol> <hr /> <h3 id="reproducible-builds-at-fosdem-2025">Reproducible Builds at FOSDEM 2025</h3> <p><a href="https://fosdem.org/2025/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/fosdem.jpeg#right" /></a></p> <p>Similar to last year’s event, there was considerable activity regarding Reproducible Builds at <a href="https://fosdem.org/2025/">FOSDEM 2025</a>, held on on 1st and 2nd February this year in Brussels, Belgium. We count at least <strong>four</strong> talks related to reproducible builds. (You can also <a href="https://reproducible-builds.org/news/2024/02/08/reproducible-builds-at-fosdem-2024/">read our news report from last year’s event</a> in which Holger Levsen presented in the main track.)</p> <p><br /></p> <p><a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6479-a-tale-of-several-distros-joining-forces-for-a-common-goal-reproducible-builds/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/fosdem-6479.png#right" /></a></p> <p>Jelle van der Waa, Holger Levsen and <em>kpcyrd</em> presented in the <em>Distributions</em> track on <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6479-a-tale-of-several-distros-joining-forces-for-a-common-goal-reproducible-builds/"><em>A Tale of several distros joining forces for a common goal</em></a>. In this talk, three developers from two different Linux distributions (Arch Linux and Debian), discuss this goal — which is, of course, reproducible builds. The presenters discuss both what is shared and different between the two efforts, touching on the history and future challenges alike. The <a href="https://reproducible-builds.org/_lfs/presentations/2025-02-02-a-tale-of-several-distros-joining-forces-for-a-common-goal-reproducible-builds/">slides of this talk</a> are available to view, as is the <a href="https://video.fosdem.org/2025/h1302/fosdem-2025-6479-a-tale-of-several-distros-joining-forces-for-a-common-goal-reproducible-builds.av1.webm">full video</a> (30m02s). The talk was also <a href="https://news.ycombinator.com/item?id=42982270">discussed on Hacker News</a>.</p> <p><br /></p> <p><a href="https://fosdem.org/2025/schedule/event/fosdem-2025-4072-rewriting-pyc-files-for-fun-and-reproducibility/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/fosdem-4072.png#right" /></a></p> <p>Zbigniew Jędrzejewski-Szmek presented in the ever-popular <em>Python</em> track a on <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-4072-rewriting-pyc-files-for-fun-and-reproducibility//"><em>Rewriting <code class="language-plaintext highlighter-rouge">.pyc</code> files for fun and reproducibility</em></a>, i.e. the bytecode files generated by Python in order to speed up module imports: “It’s been known for a while that those are not reproducible: on different architectures, the bytecode for exactly the same sources ends up slightly different.” The <a href="https://fosdem.org/2025/events/attachments/fosdem-2025-4072-rewriting-pyc-files-for-fun-and-reproducibility/slides/238866/rewriting_V75oWEe.pdf">slides of this talk</a> are available, as is the <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-4072-rewriting-pyc-files-for-fun-and-reproducibility/">full video</a> (28m32s).</p> <p><br /></p> <p>In the <em>Nix and NixOS</em> track, Julien Malka presented on the Saturday asking <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-4430-how-reproducible-is-nixos-/"><em>How reproducible is NixOS</em></a>: “We know that the NixOS ISO image is very close to be perfectly reproducible thanks to <a href="https://reproducible.nixos.org/">reproducible.nixos.org</a>, but there doesn’t exist any monitoring of Nixpkgs as a whole. In this talk I’ll present the findings of a project that evaluated the reproducibility of Nixpkgs as a whole by mass rebuilding packages from revisions between 2017 and 2023 and comparing the results with the NixOS cache.” Unfortunately, no video of the talk is available, but there is a <a href="https://luj.fr/blog/is-nixos-truly-reproducible.html">blog</a> and <a href="https://hal.science/hal-04430009">article</a> on the results.</p> <p><br /></p> <p><a href="https://fosdem.org/2025/schedule/event/fosdem-2025-5897-guix-software-heritage-source-code-archiving-to-the-rescue-of-reproducible-deployment/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/fosdem-5897.png#right" /></a></p> <p>Lastly, Simon Tournier presented in the <em>Open Research</em> track on the confluence of <a href="https://guix.gnu.org/">GNU Guix</a> and <a href="https://www.softwareheritage.org/">Software Heritage</a>: <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-5897-guix-software-heritage-source-code-archiving-to-the-rescue-of-reproducible-deployment/"><em>Source Code Archiving to the Rescue of Reproducible Deployment</em></a>. Simon’s talk “describes design and implementation we came up and reports on the archival coverage for package source code with data collected over five years. It opens to some remaining challenges toward a better open and reproducible research.” The <a href="https://fosdem.org/2025/events/attachments/fosdem-2025-5897-guix-software-heritage-source-code-archiving-to-the-rescue-of-reproducible-deployment/slides/237921/FOSDEM25-_lctdtLk.pdf">slides for the talk</a> are available, as is <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-5897-guix-software-heritage-source-code-archiving-to-the-rescue-of-reproducible-deployment/">the full video</a> (23m17s).</p> <p><br /></p> <h3 id="reproducible-builds-at-pycascades-2025">Reproducible Builds at PyCascades 2025</h3> <p><a href="https://2025.pycascades.com/program/talks/re-py-ducible-builds/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/pycascades.png#right" /></a></p> <p>Vagrant Cascadian presented at this year’s <a href="https://2025.pycascades.com/">PyCascades</a> conference which was held on February 8th and 9th February in Portland, OR, USA. PyCascades is a regional instance of <a href="https://pycon.org/">PyCon</a> held in the Pacific Northwest. Vagrant’s talk, entitled <a href="https://2025.pycascades.com/program/talks/re-py-ducible-builds/"><em>Re-Py-Ducible Builds</em></a> caught the audience’s attention with the following abstract:</p> <blockquote> <p>Crank your Python best practices up to 11 with Reproducible Builds! This talk will explore Reproducible Builds by highlighting issues identified in Python projects, from the simple to the seemingly inscrutable. Reproducible Builds is basically the crazy idea that when you build something, and you build it again, you get the exact same thing… or even more important, if someone else builds it, they get the exact same thing too.</p> </blockquote> <p>More info is available on the <a href="https://2025.pycascades.com/program/talks/re-py-ducible-builds/">talk’s page</a>.</p> <p><br /></p> <h3 id="does-functional-package-management-enable-reproducible-builds-at-scale"><em>“Does Functional Package Management Enable Reproducible Builds at Scale?”</em></h3> <p>On <a href="https://lists.reproducible-builds.org/listinfo/rb-general/">our mailing list</a> last month, Julien Malka, Stefano Zacchiroli and Théo Zimmermann of Télécom Paris’ in-house research laboratory, the <a href="https://www.telecom-paris.fr/en/research/labs/information-processing-ltci">Information Processing and Communications Laboratory</a> (LTCI) announced that they had published an article asking the question: <a href="https://hal.science/hal-04913007"><em>Does Functional Package Management Enable Reproducible Builds at Scale?</em></a> (<a href="https://hal.science/hal-04913007v1/file/2025-MSR-reproducibility.pdf">PDF</a>).</p> <p>This month, however, Ludovic Courtès followed up to the <a href="https://lists.reproducible-builds.org/pipermail/rb-general/2025-January/003653.html">original announcement on our mailing list</a> mentioning, amongst other things, the <a href="https://data.guix.gnu.org/">Guix Data Service</a> and how that it shows the reproducibility of <a href="https://guix.gnu.org/">GNU Guix</a> over time, as <a href="https://guix.gnu.org/en/blog/2024/adventures-on-the-quest-for-long-term-reproducible-deployment/">described in a GNU Guix blog</a> back in March 2024.</p> <p><br /></p> <h3 id="reproducedebiannet-updates"><a href="https://reproduce.debian.net/"><em>reproduce.debian.net</em></a> updates</h3> <p><a href="https://reproduce.debian.net"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/reproduce.png#right" /></a></p> <p>The last few months have seen the introduction of <a href="https://reproduce.debian.net"><em>reproduce.debian.net</em></a>. Announced first at the recent <a href="https://toulouse2024.mini.debconf.org/">Debian MiniDebConf in Toulouse</a>, <em>reproduce.debian.net</em> is an instance of <a href="https://github.com/kpcyrd/rebuilderd"><em>rebuilderd</em></a> operated by the Reproducible Builds project.</p> <p>Powering this work is <em>rebuilderd</em>, our server which monitors the official package repositories of Linux distributions and attempt to reproduce the observed results there. This month, however, Holger Levsen:</p> <ul> <li> <p>Split packages that are not specific to any architecture away from <em>amd64.reproducible.debian.net</em> service into a new <a href="https://all.reproduce.debian.net/"><em>all.reproducible.debian.net</em></a> page.</p> </li> <li> <p>Increased the number of <code class="language-plaintext highlighter-rouge">riscv64</code> nodes to a total of 4, and added a new <code class="language-plaintext highlighter-rouge">amd64</code> node added thanks to our (now 10-year sponsor), <a href="https://ionos.com">IONOS</a>.</p> </li> <li> <p>Discovered an issue in the <a href="https://buildd.debian.org/">Debian build service</a> where <a href="https://bugs.debian.org/1096129">some new ‘incoming’ build-dependencies do not end up historically archived</a>.</p> </li> <li> <p>Uploaded the <a href="https://salsa.debian.org/debian/devscripts"><code class="language-plaintext highlighter-rouge">devscripts</code></a> package, incorporating changes from Jochen Sprickerhof to the <code class="language-plaintext highlighter-rouge">debrebuild</code> script — specifically to fix the handling the <code class="language-plaintext highlighter-rouge">Rules-Requires-Root</code> header in Debian source packages.</p> </li> <li> <p>Uploaded a number of Rust dependencies of <em>rebuilderd</em> (<code class="language-plaintext highlighter-rouge">rust-libbz2-rs-sys</code>, <code class="language-plaintext highlighter-rouge">rust-actix-web</code>, <code class="language-plaintext highlighter-rouge">rust-actix-server</code>, <code class="language-plaintext highlighter-rouge">rust-actix-http</code>, <code class="language-plaintext highlighter-rouge">rust-actix-server</code>, <code class="language-plaintext highlighter-rouge">rust-actix-http</code>, <code class="language-plaintext highlighter-rouge">rust-actix-web-codegen</code> and <code class="language-plaintext highlighter-rouge">rust-time-tz</code>) after they were prepared by <em>kpcyrd</em> :</p> </li> </ul> <p>Jochen Sprickerhof also updated the <code class="language-plaintext highlighter-rouge">sbuild</code> package to:</p> <ul> <li>Obey requests from the user/developer for a different temporary directory.</li> <li>Use the root/superuser for some values of <code class="language-plaintext highlighter-rouge">Rules-Requires-Root</code>.</li> <li>Don’t pass <code class="language-plaintext highlighter-rouge">--root-owner-group</code> to old versions of <a href="https://wiki.debian.org/Teams/Dpkg">dpkg</a>.</li> </ul> <p>… and additionally requested that many Debian packages are <a href="https://wiki.debian.org/binNMU">rebuilt by the build servers</a> in order to work around bugs found on <a href="https://reproduce.debian.net/"><em>reproduce.debian.net</em></a>. [<a href="https://bugs.debian.org/1096112">…</a>][[<a href="https://bugs.debian.org/1092482">…</a>][<a href="https://bugs.debian.org/1093902">…</a>]</p> <p><br /></p> <p>Lastly, <em>kpcyrd</em> has also worked towards getting <a href="https://github.com/NixOS/nixpkgs/pull/343334"><em>rebuilderd</em> packaged in NixOS</a>, and Jelle van der Waa picked up the existing <a href="https://github.com/kpcyrd/rebuilderd/pull/141">pull request for Fedora support within in <em>rebuilderd</em></a> and made it work with the <a href="https://github.com/keszybz/fedora-repro-build">existing Koji <em>rebuilderd</em> script</a>. The server is being packaged for Fedora in an unofficial <a href="https://copr.fedorainfracloud.org/coprs/jelly/rebuilderd/packages/">‘copr’ repository</a> and in the official repositories after all the dependencies are packaged.</p> <p><br /></p> <h3 id="upstream-patches">Upstream patches</h3> <p>The Reproducible Builds project detects, dissects and attempts to fix as many currently-unreproducible packages as possible. We endeavour to send all of our patches upstream where appropriate. This month, we wrote a large number of such patches, including:</p> <ul> <li> <p>Andrea Manzini:</p> <ul> <li><a href="https://github.com/longbridge/rust-i18n/pull/104"><code class="language-plaintext highlighter-rouge">rust-i8n</code></a> (random <code class="language-plaintext highlighter-rouge">HashMap</code> order)</li> <li><a href="https://github.com/starship/starship/issues/6599"><code class="language-plaintext highlighter-rouge">starship/shadow</code></a></li> </ul> </li> <li> <p>Andreas Stieger:</p> <ul> <li><a href="https://build.opensuse.org/request/show/1247238"><code class="language-plaintext highlighter-rouge">tucnak</code></a></li> </ul> </li> <li> <p>Bernhard M. Wiedemann:</p> <ul> <li><a href="https://github.com/aiortc/aioquic/issues/557"><code class="language-plaintext highlighter-rouge">aioquic</code></a></li> <li><a href="https://github.com/lukaslueg/built/issues/80"><code class="language-plaintext highlighter-rouge">built</code></a></li> <li><a href="https://github.com/Wilfred/difftastic/pull/813"><code class="language-plaintext highlighter-rouge">difftastic</code></a></li> <li><a href="https://build.opensuse.org/request/show/1243016"><code class="language-plaintext highlighter-rouge">ghostscript</code></a></li> <li><a href="https://sourceforge.net/p/gputils/bugs/328/"><code class="language-plaintext highlighter-rouge">gputils/sdcc</code></a></li> <li><a href="https://build.opensuse.org/request/show/1242841"><code class="language-plaintext highlighter-rouge">hdf5</code></a></li> <li><a href="https://github.com/servo/html5ever/issues/573"><code class="language-plaintext highlighter-rouge">html5ever</code></a> (<a href="https://github.com/servo/string-cache/pull/290">fixed upstream</a>)</li> <li><a href="https://github.com/pimutils/khal/pull/1390"><code class="language-plaintext highlighter-rouge">khal</code></a></li> <li><a href="https://build.opensuse.org/request/show/1247659"><code class="language-plaintext highlighter-rouge">lkl</code></a></li> <li><a href="https://github.com/neovim/neovim/issues/32429"><code class="language-plaintext highlighter-rouge">neovim</code></a></li> <li><a href="https://build.opensuse.org/request/show/1244447"><code class="language-plaintext highlighter-rouge">nlopt</code></a></li> <li><a href="https://build.opensuse.org/request/show/1247347"><code class="language-plaintext highlighter-rouge">nushell</code></a></li> <li><a href="https://build.opensuse.org/request/show/1247180"><code class="language-plaintext highlighter-rouge">palo</code></a></li> <li><a href="https://build.opensuse.org/request/show/1245435"><code class="language-plaintext highlighter-rouge">python-numpy</code></a></li> <li><a href="https://src.opensuse.org/jengelh/schismtracker/pulls/1"><code class="language-plaintext highlighter-rouge">schismtracker</code></a></li> <li><a href="https://gitlab.com/sequoia-pgp/sequoia-sq/-/issues/535"><code class="language-plaintext highlighter-rouge">sequoia</code></a> (<a href="https://gitlab.com/sequoia-pgp/sequoia-sq/-/merge_requests/554">2</a>)</li> <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1237607"><code class="language-plaintext highlighter-rouge">tvm</code></a></li> <li><a href="https://build.opensuse.org/request/show/1243555"><code class="language-plaintext highlighter-rouge">uhd</code></a></li> <li><a href="https://sourceforge.net/p/wsjt/wsjtx/merge-requests/20/"><code class="language-plaintext highlighter-rouge">wsjtx</code></a></li> <li><a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1237094"><code class="language-plaintext highlighter-rouge">xmlgraphics-fop</code></a></li> <li><a href="https://github.com/ziglang/zig/issues/22839"><code class="language-plaintext highlighter-rouge">zig</code></a></li> </ul> </li> <li> <p>Chris Lamb:</p> <ul> <li><a href="https://bugs.debian.org/1095209">#1095209</a> filed against <a href="https://tracker.debian.org/pkg/python-assertpy"><code class="language-plaintext highlighter-rouge">python-assertpy</code></a>.</li> <li><a href="https://bugs.debian.org/1096188">#1096188</a> filed against <a href="https://tracker.debian.org/pkg/terminaltables3"><code class="language-plaintext highlighter-rouge">terminaltables3</code></a>.</li> <li><a href="https://bugs.debian.org/1098249">#1098249</a> filed against <a href="https://tracker.debian.org/pkg/acme.sh"><code class="language-plaintext highlighter-rouge">acme.sh</code></a>.</li> <li><a href="https://bugs.debian.org/1098251">#1098251</a> filed against <a href="https://tracker.debian.org/pkg/node-svgdotjs-svg.js"><code class="language-plaintext highlighter-rouge">node-svgdotjs-svg.js</code></a>.</li> <li><a href="https://bugs.debian.org/1098253">#1098253</a> filed against <a href="https://tracker.debian.org/pkg/onevpl-intel-gpu"><code class="language-plaintext highlighter-rouge">onevpl-intel-gpu</code></a>.</li> <li><a href="https://bugs.debian.org/1098350">#1098350</a> filed against <a href="https://tracker.debian.org/pkg/rocdbgapi"><code class="language-plaintext highlighter-rouge">rocdbgapi</code></a>.</li> <li><a href="https://bugs.debian.org/1098895">#1098895</a> filed against <a href="https://tracker.debian.org/pkg/siege"><code class="language-plaintext highlighter-rouge">siege</code></a>.</li> <li><a href="https://bugs.debian.org/1098945">#1098945</a> filed against <a href="https://tracker.debian.org/pkg/pkg-rocm-tools"><code class="language-plaintext highlighter-rouge">pkg-rocm-tools</code></a>.</li> </ul> </li> <li> <p>Christian Goll:</p> <ul> <li><a href="https://build.opensuse.org/request/show/1248768"><code class="language-plaintext highlighter-rouge">warewulf4</code></a> (embeds CPU core count)</li> </ul> </li> <li> <p>Jay Adddison:</p> <ul> <li><a href="https://lore.kernel.org/linux-doc/20250226203516.334067-2-jvanderw@redhat.com/"><code class="language-plaintext highlighter-rouge">linux-docs</code></a></li> </ul> </li> <li> <p>Jochen Sprickerhof:</p> <ul> <li><a href="https://bugs.debian.org/1098867">#1098867</a> filed against <a href="https://tracker.debian.org/pkg/spdlog"><code class="language-plaintext highlighter-rouge">spdlog</code></a>.</li> </ul> </li> <li> <p><em>kpcyrd</em>:</p> <ul> <li><a href="https://gitlab.archlinux.org/archlinux/packaging/packages/perl/-/commit/b2ac4e7b8d71463f8e2944693b5f27640d88b444"><code class="language-plaintext highlighter-rouge">perl</code></a> (hostname)</li> <li><a href="https://gitlab.archlinux.org/archlinux/packaging/packages/pam/-/commit/bc4528c28672fe75a1378e4834bf58ae7889caee"><code class="language-plaintext highlighter-rouge">pam</code></a> (timestamp)</li> </ul> </li> <li> <p>Leonidas Spyropoulos:</p> <ul> <li><a href="https://gitlab.archlinux.org/archlinux/packaging/packages/curl/-/commit/cb7452f4c8dfb3a88b9732d45c359a7a118ec907"><code class="language-plaintext highlighter-rouge">curl</code></a> ( (<a href="https://github.com/curl/curl/issues/16072">bug</a>, terminal size undeterministic)</li> </ul> </li> <li> <p>Robin Candau (Antiz):</p> <ul> <li><a href="https://gitlab.com/saalen/highlight/-/merge_requests/151"><code class="language-plaintext highlighter-rouge">highlight</code></a> (timestamp)</li> <li><a href="https://gitlab.archlinux.org/grawlinson/arch-wiki-lite/-/merge_requests/2"><code class="language-plaintext highlighter-rouge">arch-wiki-lite</code></a> (timestamp)</li> <li><a href="https://github.com/f3d-app/f3d/pull/1982"><code class="language-plaintext highlighter-rouge">f3d</code></a> (timestamp)</li> <li><a href="https://github.com/jacktrip/jacktrip/pull/1394"><code class="language-plaintext highlighter-rouge">jacktrip</code></a> (timestamp)</li> <li><a href="https://github.com/prometheus/prometheus/pull/16035"><code class="language-plaintext highlighter-rouge">prometheus</code></a> (timestamp)</li> </ul> </li> <li> <p>Wolfgang Frisch:</p> <ul> <li><a href="https://build.opensuse.org/request/show/1245248"><code class="language-plaintext highlighter-rouge">bcc</code></a> (instruct Lua to be deterministic)</li> <li><a href="https://github.com/crash-utility/crash/pull/200"><code class="language-plaintext highlighter-rouge">crash</code></a> (<code class="language-plaintext highlighter-rouge">Makefile</code> race)</li> </ul> </li> <li> <p>Hongxu Jia:</p> <ul> <li><a href="https://go-review.googlesource.com/c/go/+/653895"><code class="language-plaintext highlighter-rouge">go</code></a> (clear GOROOT for func ldShared when -trimpath is used)</li> </ul> </li> </ul> <p><br /></p> <h3 id="distribution-work">Distribution work</h3> <p>There as been the usual work in various distributions this month, such as:</p> <p><a href="https://debian.org/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/debian.png#right" /></a></p> <p>In <strong>Debian</strong>, 17 reviews of Debian packages were added, 6 were updated and 8 were removed this month adding to <a href="https://tests.reproducible-builds.org/debian/index_issues.html">our knowledge about identified issues</a>.</p> <p><br /></p> <p><strong><a href="https://fedoraproject.org/">Fedora</a></strong> developers Davide Cavalca and Zbigniew Jędrzejewski-Szmek gave a talk on <a href="https://cfp.fedoraproject.org/media/flock-2024/submissions/SKWEXP/resources/Reproducible_builds_in_Fedora_Flock_2024_Iiyoq3s.pdf"><em>Reproducible Builds in Fedora</em></a> (PDF), touching on <a href="https://en.wikipedia.org/wiki/RPM_Package_Manager#SRPM">SRPM</a>-specific issues as well as the current status and future plans.</p> <p><br /></p> <p><a href="https://freebsd.org/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/freebsd.png#right" /></a></p> <p>Thanks to an investment from the <a href="https://freebsdfoundation.org/blog/zero-trust-builds-for-freebsd/">Sovereign Tech Agency</a>, the <strong><a href="https://www.freebsd.org/">FreeBSD</a></strong> project’s work on unprivileged and reproducible builds continued this month. Notable fixes include:</p> <ul> <li><a href="https://github.com/freebsd/pkg/commit/ea82e1d6df919714a2e3472c7561f53a2dde69d1"><code class="language-plaintext highlighter-rouge">pkg</code></a> (hash ordering)</li> <li><a href="https://cgit.freebsd.org/src/commit/usr.sbin/makefs/cd9660?id=518cdd344ec51584478f39b9a9cac77fc0766ce1"><code class="language-plaintext highlighter-rouge">makefs</code></a> (source filesystem inode number leakage)</li> <li><a href="https://cgit.freebsd.org/src/commit/?id=8a3537aaf7c19f7331fcc160ab42e36fc79e408a"><code class="language-plaintext highlighter-rouge">FreeBSD base system packages</code></a> (timestamp)</li> </ul> <p><br /></p> <p><a href="https://yoctoproject.org/">The <strong>Yocto Project</strong></a> has been struggling to upgrade to the latest <a href="https://go.dev/">Go</a> and <a href="https://www.rust-lang.org/">Rust</a> releases due to reproducibility problems in the newer versions. Hongxu Jia tracked down the issue with Go which meant that the project could upgrade from the 1.22 series to 1.24, with the fix being submitted upstream for review (see above). For Rust, however, the project was significantly behind, but has made recent progress after finally identifying the blocking reproducibility issues. At time of writing, the project is at Rust version 1.82, with patches under review for 1.83 and 1.84 and fixes being discussed with the Rust developers. The project hopes to improve the tests for reproducibility in the Rust project itself in order to try and avoid future regressions.</p> <p>Yocto continues to maintain its ability to binary reproduce all of the recipes in <a href="https://www.yoctoproject.org/reproducible-build-results/">OpenEmbedded-Core</a>, regardless of the build host distribution or the current build path.</p> <p><br /></p> <p><a href="https://www.opensuse.org/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/opensuse.png#right" /></a></p> <p>Finally, Douglas DeMaio published an article on the <a href="https://news.opensuse.org/"><strong>openSUSE</strong> blog</a> on announcing that the <a href="https://news.opensuse.org/2025/02/18/rbos-project-hits-milestone/"><em>Reproducible-openSUSE (RBOS) Project Hits [Significant] Milestone</em></a>. In particular:</p> <blockquote> <p>The <a href="https://en.opensuse.org/openSUSE:Reproducible_openSUSE">Reproducible-openSUSE (RBOS)</a> project, which is a proof-of-concept fork of openSUSE, has reached a significant milestone after demonstrating a usable Linux distribution can be built with 100% bit-identical packages.</p> </blockquote> <p>This news was <a href="https://lists.reproducible-builds.org/pipermail/rb-general/2025-February/003661.html">also announced on our mailing list</a> by Bernhard M. Wiedemann, who also <a href="https://lists.opensuse.org/archives/list/factory@lists.opensuse.org/thread/3VT2UY7YUIM3AP3XIQAYO32VT7KZ7FBK/">published another report</a> for openSUSE as well.</p> <p><br /></p> <h3 id="diffoscope--strip-nondeterminism"><a href="https://diffoscope.org"><em>diffoscope</em></a> & <em>strip-nondeterminism</em></h3> <p><a href="https://diffoscope.org/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/diffoscope.png#right" /></a></p> <p><a href="https://diffoscope.org">diffoscope</a> is our in-depth and content-aware diff utility that can locate and diagnose reproducibility issues. This month, Chris Lamb made the following changes, including preparing and uploading versions <code class="language-plaintext highlighter-rouge">288</code> and <code class="language-plaintext highlighter-rouge">289</code> to Debian:</p> <ul> <li>Add <code class="language-plaintext highlighter-rouge">asar</code> to <code class="language-plaintext highlighter-rouge">DIFFOSCOPE_FAIL_TESTS_ON_MISSING_TOOLS</code> in order to address Debian bug <a href="https://bugs.debian.org/1095057"><code class="language-plaintext highlighter-rouge">#1095057</code></a>) [<a href="https://salsa.debian.org/reproducible-builds/diffoscope/commit/79ff322e">…</a>]</li> <li>Catch a <code class="language-plaintext highlighter-rouge">CalledProcessError</code> when calling <code class="language-plaintext highlighter-rouge">html2text</code>. [<a href="https://salsa.debian.org/reproducible-builds/diffoscope/commit/e470ee25">…</a>]</li> <li>Update the minimal <a href="https://black.readthedocs.io/en/stable/"><em>Black</em></a> version. [<a href="https://salsa.debian.org/reproducible-builds/diffoscope/commit/c5aa1ff5">…</a>]</li> </ul> <p>Additionally, Vagrant Cascadian updated <em>diffoscope</em> in <a href="https://guix.gnu.org/">GNU Guix</a> to version 287 [<a href="https://debbugs.gnu.org/76080">…</a>][<a href="https://git.savannah.gnu.org/cgit/guix.git/commit/?id=27c2b2f1a6f48f238030893b6d0ebc9c2bc68b12">…</a>] and 288 [<a href="https://debbugs.gnu.org/76122">…</a>][<a href="https://git.savannah.gnu.org/cgit/guix.git/commit/?id=d304311a3949795659bf08d9409ddf86481dcc36">…</a>] as well as submitted a patch to update to 289 [<a href="https://debbugs.gnu.org/76599">…</a>]. Vagrant also fixed an issue that was breaking <em>reprotest</em> on Guix [<a href="https://debbugs.gnu.org/76602">…</a>][<a href="https://git.savannah.gnu.org/cgit/guix.git/commit/?id=2558392803663f4381fa9c09a53d329b719152bd">…</a>].</p> <p><a href="https://salsa.debian.org/reproducible-builds/strip-nondeterminism"><em>strip-nondeterminism</em></a> is our sister tool to remove specific non-deterministic results from a completed build. This month version <code class="language-plaintext highlighter-rouge">1.14.1-2</code> was <a href="https://tracker.debian.org/news/1614424/accepted-strip-nondeterminism-1141-2-source-into-unstable/">uploaded to Debian unstable</a> by Holger Levsen.</p> <p><br /></p> <h3 id="website-updates">Website updates</h3> <p><a href="https://reproducible-builds.org/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-02/website.png#right" /></a></p> <p>There were a large number of improvements made to our website this month, including:</p> <ul> <li> <p>Bernhard M. Wiedemann fixed an issue on the <a href="https://reproducible-builds.org/docs/commandments/"><em>Commandments of reproducible builds</em></a> fixing a link to the <a href="https://github.com/bmwiedemann/theunreproduciblepackage/tree/master/readdir"><code class="language-plaintext highlighter-rouge">readdir</code></a> component of Bernhard’s own <a href="https://github.com/bmwiedemann/theunreproduciblepackage">Unreproducible Package</a>. [<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/bf9274a0">…</a>]</p> </li> <li> <p>Holger Levsen clarified the name of a link to our old Wiki pages on the <a href="https://reproducible-builds.org/docs/history/"><em>History</em></a> page [<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/0fb66ed9">…</a>] and added a number of new links to the <a href="https://reproducible-builds.org/resources/"><em>Talks & Resources</em></a> page [<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/33b9594d">…</a>][<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/f7e5a9c9">…</a>].</p> </li> <li> <p>James Addison update the website’s own <a href="https://salsa.debian.org/reproducible-builds/reproducible-website#readme"><code class="language-plaintext highlighter-rouge">README</code></a> file to document a couple of additional dependencies [<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/308373c2">…</a>][<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/ceee7b28">…</a>], as well as did more work on a future <em>Getting Started</em> guide page [<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/61d6ab62">…</a>][<a href="https://salsa.debian.org/reproducible-builds/reproducible-website/commit/23f28585">…</a>].</p> </li> </ul> <p><br /></p> <h3 id="reproducibility-testing-framework">Reproducibility testing framework</h3> <p><a href="https://tests.reproducible-builds.org/"><img alt="" src="https://reproducible-builds.org/images/reports/2025-01/testframework.png#right" /></a></p> <p>The Reproducible Builds project operates a comprehensive testing framework running primarily at <a href="https://tests.reproducible-builds.org"><em>tests.reproducible-builds.org</em></a> in order to check packages and other artifacts for reproducibility. In January, a number of changes were made by Holger Levsen, including:</p> <ul> <li> <p><a href="https://reproduce.debian.net"><em>reproduce.debian.net</em></a>-related:</p> <ul> <li>Add a helper script to manually schedule packages. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/2a0687142">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/cb69118bc">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/30f376fbf">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/fc11778d8">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/871d7c509">…</a>]</li> <li>Fix a link in the website footer. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/1e4731b40">…</a>]</li> <li>Strip the “💠🍥♻” emojis from package names on the manual rebuilder in order to ease copy-and-paste. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/bdaeaf460">…</a>]</li> <li>On the various statistics pages, provide the number of affected source packages [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/d6538620d">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/daabe3cf6">…</a>] as well as provide various totals [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/f6f2be8e0">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/4a622a4f5">…</a>].</li> <li>Fix graph labels for the various architectures [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/be76b69dd">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/cb3d39cf0">…</a>] and make them clickable too [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/0f141d2e1">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/8a610a2eb">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/bed9b4e31">…</a>].</li> <li>Break the displayed HTML in blocks of 256 packages in order to address rendering issues. [<a href="https://salsa.debian.orgqa/jenkins.debian.net/commit/0fa4fc68f">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/fe9d6a854">…</a>]</li> <li>Add monitoring jobs for <code class="language-plaintext highlighter-rouge">riscv64</code> archicture nodes and integrate them elsewhere in our infrastructure. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/675f6a11b">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/a486b7447">…</a>]</li> <li>Add <code class="language-plaintext highlighter-rouge">riscv64</code> architecture nodes. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/5fd63d56a">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/f5c3650eb">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/a7d52658e">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/e703fe971">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/156a0c6c8">…</a>]</li> <li>Update much of the documentation. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/557979a6e">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/ec9b33414">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/4f0f31b36">…</a>]</li> <li>Make a number of improvements to the layout and style. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/a52fa4e2c">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/c6b096ef7">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/4419a6619">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/39ee08ebe">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/f2826eb71">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/908c5b967">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/966a2860a">…</a>]</li> <li>Remove direct links to JSON and database backups. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/5bf4c02f5">…</a>]</li> <li>Drop a <a href="https://en.wikipedia.org/wiki/The_Blues_Brothers">Blues Brothers</a> reference from frontpage. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/e1a06c522">…</a>]</li> </ul> </li> <li> <p><a href="https://debian.org/">Debian</a>-related:</p> <ul> <li>Deal with <code class="language-plaintext highlighter-rouge">/boot/vmlinuz*</code> being called <code class="language-plaintext highlighter-rouge">vmlinux*</code> on the <code class="language-plaintext highlighter-rouge">riscv64</code> architecture. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/ebe31528a">…</a>]</li> <li>Add a new <code class="language-plaintext highlighter-rouge">ionos17</code> node. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/05ce176a2">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/f63f2bcc1">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/4e223a51c">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/4d405000b">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/f455f7963">…</a>]</li> <li>Install <code class="language-plaintext highlighter-rouge">debian-repro-status</code> on all Debian <em>trixie</em> and <em>unstable</em> jobs. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/8d3f6120f">…</a>]</li> </ul> </li> <li> <p><a href="https://www.freebsd.org/">FreeBSD</a>-related:</p> <ul> <li>Switch to run latest branch of FreeBSD. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/384e1ea79">…</a>]</li> </ul> </li> <li> <p>Misc:</p> <ul> <li>Fix <code class="language-plaintext highlighter-rouge">/etc/cron.d</code> and <code class="language-plaintext highlighter-rouge">/etc/logrotate.d</code> permissions for Jenkins nodes. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/b4c4c10f4">…</a>]</li> <li>Add support for <code class="language-plaintext highlighter-rouge">riscv64</code> architecture nodes. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/4779831fc">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/7ec069881">…</a>]</li> <li>Grant Jochen Sprickerhof access to the <code class="language-plaintext highlighter-rouge">o4</code> node. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/ca539b3cf">…</a>]</li> <li>Disable the <code class="language-plaintext highlighter-rouge">janitor-setup-worker</code>. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/4d6156e3d">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/b6a514ea0">…</a>]</li> </ul> </li> </ul> <p>In addition:</p> <ul> <li> <p><em>kpcyrd</em> fixed the <code class="language-plaintext highlighter-rouge">/all/api/</code> API endpoints on <a href="https://reproduce.debian.net"><em>reproduce.debian.net</em></a> by altering the <a href="https://nginx.org/">nginx</a> configuration. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/e62b098f4">…</a>]</p> </li> <li> <p>James Addison updated <a href="https://reproduce.debian.net"><em>reproduce.debian.net</em></a> to display the so-called ‘bad’ reasons hyperlink inline [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/e5a9e8749">…</a>] and merged the “Categorized issues” links into the “Reproduced builds” column [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/f4d2cc828">…</a>].</p> </li> <li> <p>Jochen Sprickerhof also made some <a href="https://reproduce.debian.net"><em>reproduce.debian.net</em></a>-related changes, adding support for detecting a <a href="http://bugs.debian.org/1094165">bug in the <code class="language-plaintext highlighter-rouge">mmdebstrap</code></a> package [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/53d49a31a">…</a>] as well as updating some documentation [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/eda9b4f37">…</a>].</p> </li> <li> <p>Roland Clobus continued their work on reproducible ‘live’ images for Debian, making changes related to new clustering of jobs in <a href="https://open.qa/">openQA</a>. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/aafcf255e">…</a>]</p> </li> </ul> <p>And finally, both Holger Levsen [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/042c2ec6c">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/2a7d73ef9">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/3346f409e">…</a>] and Vagrant Cascadian performed significant node maintenance. [<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/5be92d0ff">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/26b34a93e">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/e74e53f71">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/b2c55e610">…</a>][<a href="https://salsa.debian.org/qa/jenkins.debian.net/commit/58ae0663f">…</a>]</p> <p><br /></p> <p>If you are interested in contributing to the Reproducible Builds project, please visit our <a href="https://reproducible-builds.org/contribute/"><em>Contribute</em></a> page on our website. However, you can get in touch with us via:</p> <ul> <li> <p>IRC: <code class="language-plaintext highlighter-rouge">#reproducible-builds</code> on <code class="language-plaintext highlighter-rouge">irc.oftc.net</code>.</p> </li> <li> <p>Mastodon: <a href="https://fosstodon.org/@reproducible_builds">@reproducible_builds@fosstodon.org</a></p> </li> <li> <p>Mailing list: <a href="https://lists.reproducible-builds.org/listinfo/rb-general"><code class="language-plaintext highlighter-rouge">rb-general@lists.reproducible-builds.org</code></a></p> </li> <li> <p>Twitter/X: <a href="https://twitter.com/ReproBuilds">@ReproBuilds</a></p> </li> </ul> </div> <p class="date"> <a href="https://reproducible-builds.org/reports/2025-02/">05 March, 2025 01:31PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <h2 class="planet-title"> <a href="http://notes.secretsauce.net" title="Dima Kogan">Dima Kogan</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html_hide\" onClick=\"exclude( 'http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html_show\" style=\"display:none;\" onClick=\"show( 'http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html" class="http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html"> <div class="entry"> <h3 class="entry-title"> <a href="http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html">Shop scheduling with PuLP</a> </h3> <div class="content"> <p> I recently used the <a href="https://coin-or.github.io/pulp/">PuLP modeler</a> to solve a work scheduling problem to assign workers to shifts. Here are notes about doing that. This is a common use case, but isn't explicitly covered in the <a href="https://coin-or.github.io/pulp/CaseStudies/index.html">case studies</a> in the PuLP documentation. </p> <p> Here's the problem: </p> <ul class="org-ul"> <li>We are trying to put together a schedule for one week </li> <li>Each day has some set of work shifts that need to be staffed </li> <li>Each shift must be staffed with <i>exactly</i> one worker </li> <li>The shift schedule is known beforehand, and the workers each declare their preferences beforehand: they mark each shift in the week as one of: <ul class="org-ul"> <li>PREFERRED (if they want to be scheduled on that shift) </li> <li>NEUTRAL </li> <li>DISFAVORED (if they don't love that shift) </li> <li>REFUSED (if they absolutely cannot work that shift) </li> </ul> </li> </ul> <p> The tool is supposed to allocate workers to the shifts to try to cover all the shifts, give everybody work, and try to match their preferences. I implemented the tool: </p> <div class="org-src-container"> <pre class="src src-python"><span style="color: #cdcd00;">#</span><span style="color: #cdcd00;">!/usr/bin/python3</span> <span style="color: #00cdcd; font-weight: bold;">import</span> sys <span style="color: #00cdcd; font-weight: bold;">import</span> os <span style="color: #00cdcd; font-weight: bold;">import</span> re <span style="color: #00cdcd; font-weight: bold;">def</span> <span style="color: #0000ee; font-weight: bold;">report_solution_to_console</span>(<span style="color: #0000ee; font-weight: bold;">vars</span>): <span style="color: #00cdcd; font-weight: bold;">for</span> w <span style="color: #00cdcd; font-weight: bold;">in</span> days_of_week: <span style="color: #cdcd00;">annotation</span> = <span style="color: #00cd00;">''</span> <span style="color: #00cdcd; font-weight: bold;">if</span> human_annotate <span style="color: #00cdcd; font-weight: bold;">is</span> <span style="color: #00cdcd; font-weight: bold;">not</span> <span style="color: #cd00cd;">None</span>: <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys(): <span style="color: #cdcd00;">m</span> = re.match(rf<span style="color: #00cd00;">'{w} - '</span>, s) <span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #00cdcd; font-weight: bold;">not</span> m: <span style="color: #00cdcd; font-weight: bold;">continue</span> <span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #0000ee; font-weight: bold;">vars</span>[human_annotate][s].value(): <span style="color: #cdcd00;">annotation</span> = f<span style="color: #00cd00;">" ({human_annotate} SCHEDULED)"</span> <span style="color: #00cdcd; font-weight: bold;">break</span> <span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #00cdcd; font-weight: bold;">not</span> <span style="color: #0000ee; font-weight: bold;">len</span>(annotation): <span style="color: #cdcd00;">annotation</span> = f<span style="color: #00cd00;">" ({human_annotate} OFF)"</span> <span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">"{w}{annotation}"</span>) <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys(): <span style="color: #cdcd00;">m</span> = re.match(rf<span style="color: #00cd00;">'{w} - '</span>, s) <span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #00cdcd; font-weight: bold;">not</span> m: <span style="color: #00cdcd; font-weight: bold;">continue</span> <span style="color: #cdcd00;">annotation</span> = <span style="color: #00cd00;">''</span> <span style="color: #00cdcd; font-weight: bold;">if</span> human_annotate <span style="color: #00cdcd; font-weight: bold;">is</span> <span style="color: #00cdcd; font-weight: bold;">not</span> <span style="color: #cd00cd;">None</span>: <span style="color: #cdcd00;">annotation</span> = f<span style="color: #00cd00;">" ({human_annotate} {shifts[s][human_annotate]})"</span> <span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">" ---- {s[m.end():]}{annotation}"</span>) <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #0000ee; font-weight: bold;">vars</span>[h][s].value(): <span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">" {h} ({shifts[s][h]})"</span>) <span style="color: #00cdcd; font-weight: bold;">def</span> <span style="color: #0000ee; font-weight: bold;">report_solution_summary_to_console</span>(<span style="color: #0000ee; font-weight: bold;">vars</span>): <span style="color: #00cdcd; font-weight: bold;">print</span>(<span style="color: #00cd00;">"\nSUMMARY"</span>) <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">"-- {h}"</span>) <span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">" benefit: {benefits[h].value():.3f}"</span>) <span style="color: #cdcd00;">counts</span> = <span style="color: #0000ee; font-weight: bold;">dict</span>() <span style="color: #00cdcd; font-weight: bold;">for</span> a <span style="color: #00cdcd; font-weight: bold;">in</span> availabilities: <span style="color: #cdcd00;">counts</span>[a] = 0 <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys(): <span style="color: #00cdcd; font-weight: bold;">if</span> <span style="color: #0000ee; font-weight: bold;">vars</span>[h][s].value(): counts[shifts[s][h]] += 1 <span style="color: #00cdcd; font-weight: bold;">for</span> a <span style="color: #00cdcd; font-weight: bold;">in</span> availabilities: <span style="color: #00cdcd; font-weight: bold;">print</span>(f<span style="color: #00cd00;">" {counts[a]} {a}"</span>) <span style="color: #cdcd00;">human_annotate</span> = <span style="color: #cd00cd;">None</span> <span style="color: #cdcd00;">days_of_week</span> = (<span style="color: #00cd00;">'SUNDAY'</span>, <span style="color: #00cd00;">'MONDAY'</span>, <span style="color: #00cd00;">'TUESDAY'</span>, <span style="color: #00cd00;">'WEDNESDAY'</span>, <span style="color: #00cd00;">'THURSDAY'</span>, <span style="color: #00cd00;">'FRIDAY'</span>, <span style="color: #00cd00;">'SATURDAY'</span>) <span style="color: #cdcd00;">humans</span> = [<span style="color: #00cd00;">'ALICE'</span>, <span style="color: #00cd00;">'BOB'</span>, <span style="color: #00cd00;">'CAROL'</span>, <span style="color: #00cd00;">'DAVID'</span>, <span style="color: #00cd00;">'EVE'</span>, <span style="color: #00cd00;">'FRANK'</span>, <span style="color: #00cd00;">'GRACE'</span>, <span style="color: #00cd00;">'HEIDI'</span>, <span style="color: #00cd00;">'IVAN'</span>, <span style="color: #00cd00;">'JUDY'</span>] <span style="color: #cdcd00;">shifts</span> = {<span style="color: #00cd00;">'SUNDAY - SANDING 9:00 AM - 4:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>}, <span style="color: #00cd00;">'WEDNESDAY - SAWING 7:30 AM - 2:30 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'THURSDAY - SANDING 9:00 AM - 4:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>}, <span style="color: #00cd00;">'SATURDAY - SAWING 7:30 AM - 2:30 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SUNDAY - SAWING 9:00 AM - 4:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'MONDAY - SAWING 9:00 AM - 4:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'TUESDAY - SAWING 9:00 AM - 4:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'WEDNESDAY - PAINTING 7:30 AM - 2:30 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'THURSDAY - SAWING 9:00 AM - 4:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'FRIDAY - SAWING 9:00 AM - 4:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SATURDAY - PAINTING 7:30 AM - 2:30 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SUNDAY - PAINTING 9:45 AM - 4:45 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'MONDAY - PAINTING 9:45 AM - 4:45 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'TUESDAY - PAINTING 9:45 AM - 4:45 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'WEDNESDAY - SANDING 9:45 AM - 4:45 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'THURSDAY - PAINTING 9:45 AM - 4:45 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'FRIDAY - PAINTING 9:45 AM - 4:45 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SATURDAY - SANDING 9:45 AM - 4:45 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SUNDAY - PAINTING 11:00 AM - 6:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'MONDAY - PAINTING 12:00 PM - 7:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'TUESDAY - PAINTING 12:00 PM - 7:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'WEDNESDAY - PAINTING 12:00 PM - 7:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'THURSDAY - PAINTING 12:00 PM - 7:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'FRIDAY - PAINTING 12:00 PM - 7:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SATURDAY - PAINTING 12:00 PM - 7:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SUNDAY - SAWING 12:00 PM - 7:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'MONDAY - SAWING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'TUESDAY - SAWING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'WEDNESDAY - SAWING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'THURSDAY - SAWING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'FRIDAY - SAWING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SATURDAY - SAWING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SUNDAY - PAINTING 12:15 PM - 7:15 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'MONDAY - PAINTING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'TUESDAY - PAINTING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'WEDNESDAY - PAINTING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'THURSDAY - PAINTING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'FRIDAY - PAINTING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}, <span style="color: #00cd00;">'SATURDAY - PAINTING 2:00 PM - 9:00 PM'</span>: {<span style="color: #00cd00;">'ALICE'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'BOB'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'CAROL'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'FRANK'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'HEIDI'</span>: <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'IVAN'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'JUDY'</span>: <span style="color: #00cd00;">'DISFAVORED'</span>, <span style="color: #00cd00;">'EVE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'GRACE'</span>: <span style="color: #00cd00;">'REFUSED'</span>, <span style="color: #00cd00;">'DAVID'</span>: <span style="color: #00cd00;">'REFUSED'</span>}} <span style="color: #cdcd00;">availabilities</span> = [<span style="color: #00cd00;">'PREFERRED'</span>, <span style="color: #00cd00;">'NEUTRAL'</span>, <span style="color: #00cd00;">'DISFAVORED'</span>] <span style="color: #00cdcd; font-weight: bold;">import</span> pulp <span style="color: #cdcd00;">prob</span> = pulp.LpProblem(<span style="color: #00cd00;">"Scheduling"</span>, pulp.LpMaximize) <span style="color: #0000ee; font-weight: bold;">vars</span> = pulp.LpVariable.dicts(<span style="color: #00cd00;">"Assignments"</span>, (humans, shifts.keys()), <span style="color: #cd00cd;">None</span>,<span style="color: #cd00cd;">None</span>, <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">bounds; unused, since these are binary variables</span> pulp.LpBinary) <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">Everyone works at least 2 shifts</span> <span style="color: #cdcd00;">Nshifts_min</span> = 2 <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #cdcd00;">prob</span> += ( pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys()]) >= Nshifts_min, f<span style="color: #00cd00;">"{h} works at least {Nshifts_min} shifts"</span>, ) <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">each shift is ~ 8 hours, so I limit everyone to 40/8 = 5 shifts</span> <span style="color: #cdcd00;">Nshifts_max</span> = 5 <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #cdcd00;">prob</span> += ( pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys()]) <= Nshifts_max, f<span style="color: #00cd00;">"{h} works at most {Nshifts_max} shifts"</span>, ) <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">all shifts staffed and not double-staffed</span> <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys(): <span style="color: #cdcd00;">prob</span> += ( pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans]) == 1, f<span style="color: #00cd00;">"{s} is staffed"</span>, ) <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">each human can work at most one shift on any given day</span> <span style="color: #00cdcd; font-weight: bold;">for</span> w <span style="color: #00cdcd; font-weight: bold;">in</span> days_of_week: <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #cdcd00;">prob</span> += ( pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys() <span style="color: #00cdcd; font-weight: bold;">if</span> re.match(rf<span style="color: #00cd00;">'{w} '</span>,s)]) <= 1, f<span style="color: #00cd00;">"{h} cannot be double-booked on {w}"</span> ) <span style="color: #cdcd00;">#### </span><span style="color: #cdcd00;">Some explicit constraints; as an example</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">DAVID can't work any PAINTING shift and is off on Thu and Sun</span> <span style="color: #cdcd00;">h</span> = <span style="color: #00cd00;">'DAVID'</span> <span style="color: #cdcd00;">prob</span> += ( pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys() <span style="color: #00cdcd; font-weight: bold;">if</span> re.search(r<span style="color: #00cd00;">'- PAINTING'</span>,s)]) == 0, f<span style="color: #00cd00;">"{h} can't work any PAINTING shift"</span> ) <span style="color: #cdcd00;">prob</span> += ( pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys() <span style="color: #00cdcd; font-weight: bold;">if</span> re.match(r<span style="color: #00cd00;">'THURSDAY|SUNDAY'</span>,s)]) == 0, f<span style="color: #00cd00;">"{h} is off on Thursday and Sunday"</span> ) <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">Do not assign any "REFUSED" shifts</span> <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys(): <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #00cdcd; font-weight: bold;">if</span> shifts[s][h] == <span style="color: #00cd00;">'REFUSED'</span>: <span style="color: #cdcd00;">prob</span> += ( <span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] == 0, f<span style="color: #00cd00;">"{h} is not available for {s}"</span> ) <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">Objective. I try to maximize the "happiness". Each human sees each shift as</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">one of:</span> <span style="color: #cdcd00;">#</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">PREFERRED</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">NEUTRAL</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">DISFAVORED</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">REFUSED</span> <span style="color: #cdcd00;">#</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">I set a hard constraint to handle "REFUSED", and arbitrarily, I set these</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">benefit values for the others</span> <span style="color: #cdcd00;">benefit_availability</span> = <span style="color: #0000ee; font-weight: bold;">dict</span>() <span style="color: #cdcd00;">benefit_availability</span>[<span style="color: #00cd00;">'PREFERRED'</span>] = 3 <span style="color: #cdcd00;">benefit_availability</span>[<span style="color: #00cd00;">'NEUTRAL'</span>] = 2 <span style="color: #cdcd00;">benefit_availability</span>[<span style="color: #00cd00;">'DISFAVORED'</span>] = 1 <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">Not used, since this is a hard constraint. But the code needs this to be a</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">part of the benefit. I can ignore these in the code, but let's keep this</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">simple</span> <span style="color: #cdcd00;">benefit_availability</span>[<span style="color: #00cd00;">'REFUSED'</span> ] = -1000 <span style="color: #cdcd00;">benefits</span> = <span style="color: #0000ee; font-weight: bold;">dict</span>() <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #cdcd00;">benefits</span>[h] = \ pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] * benefit_availability[shifts[s][h]] \ <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys()]) <span style="color: #cdcd00;">benefit_total</span> = \ pulp.lpSum([benefits[h] \ <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans]) <span style="color: #cdcd00;">prob</span> += ( benefit_total, <span style="color: #00cd00;">"happiness"</span>, ) prob.solve() <span style="color: #00cdcd; font-weight: bold;">if</span> pulp.LpStatus[prob.status] == <span style="color: #00cd00;">"Optimal"</span>: report_solution_to_console(<span style="color: #0000ee; font-weight: bold;">vars</span>) report_solution_summary_to_console(<span style="color: #0000ee; font-weight: bold;">vars</span>) </pre> </div> <p> The set of workers is in the <code>humans</code> variable, and the shift schedule and the workers' preferences are encoded in the <code>shifts</code> dict. The problem is defined by a <code>vars</code> dict of dicts, each a boolean variable indicating whether a particular worker is scheduled for a particular shift. We define a set of constraints to these worker allocations to restrict ourselves to <i>valid</i> solutions. And among these valid solutions, we try to find the one that maximizes some <i>benefit</i> function, defined here as: </p> <div class="org-src-container"> <pre class="src src-python"><span style="color: #cdcd00;">benefit_availability</span> = <span style="color: #0000ee; font-weight: bold;">dict</span>() <span style="color: #cdcd00;">benefit_availability</span>[<span style="color: #00cd00;">'PREFERRED'</span>] = 3 <span style="color: #cdcd00;">benefit_availability</span>[<span style="color: #00cd00;">'NEUTRAL'</span>] = 2 <span style="color: #cdcd00;">benefit_availability</span>[<span style="color: #00cd00;">'DISFAVORED'</span>] = 1 <span style="color: #cdcd00;">benefits</span> = <span style="color: #0000ee; font-weight: bold;">dict</span>() <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #cdcd00;">benefits</span>[h] = \ pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] * benefit_availability[shifts[s][h]] \ <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys()]) <span style="color: #cdcd00;">benefit_total</span> = \ pulp.lpSum([benefits[h] \ <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans]) </pre> </div> <p> So for instance each shift that was scheduled as somebody's PREFERRED shift gives us 3 benefit points. And if all the shifts ended up being PREFERRED, we'd have a total benefit value of 3*Nshifts. This is impossible, however, because that would violate some constraints in the problem. </p> <p> The exact trade-off between the different preferences is set in the <code>benefit_availability</code> dict. With the above numbers, it's equally good for somebody to have a NEUTRAL shift and a day off as it is for them to have DISFAVORED shifts. If we really want to encourage the program to work people as much as possible (days off discouraged), we'd want to raise the DISFAVORED threshold. </p> <p> I run this program and I get: </p> <pre class="example">.... Result - Optimal solution found Objective value: 108.00000000 Enumerated nodes: 0 Total iterations: 0 Time (CPU seconds): 0.01 Time (Wallclock seconds): 0.01 Option for printingOptions changed from normal to all Total time (CPU seconds): 0.02 (Wallclock seconds): 0.02 SUNDAY ---- SANDING 9:00 AM - 4:00 PM EVE (PREFERRED) ---- SAWING 9:00 AM - 4:00 PM IVAN (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM FRANK (PREFERRED) ---- PAINTING 11:00 AM - 6:00 PM HEIDI (PREFERRED) ---- SAWING 12:00 PM - 7:00 PM ALICE (PREFERRED) ---- PAINTING 12:15 PM - 7:15 PM CAROL (PREFERRED) MONDAY ---- SAWING 9:00 AM - 4:00 PM DAVID (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM IVAN (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM GRACE (PREFERRED) ---- SAWING 2:00 PM - 9:00 PM ALICE (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM HEIDI (NEUTRAL) TUESDAY ---- SAWING 9:00 AM - 4:00 PM DAVID (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM EVE (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM FRANK (NEUTRAL) ---- SAWING 2:00 PM - 9:00 PM BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM HEIDI (NEUTRAL) WEDNESDAY ---- SAWING 7:30 AM - 2:30 PM DAVID (PREFERRED) ---- PAINTING 7:30 AM - 2:30 PM IVAN (PREFERRED) ---- SANDING 9:45 AM - 4:45 PM FRANK (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM JUDY (PREFERRED) ---- SAWING 2:00 PM - 9:00 PM BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM ALICE (NEUTRAL) THURSDAY ---- SANDING 9:00 AM - 4:00 PM GRACE (PREFERRED) ---- SAWING 9:00 AM - 4:00 PM CAROL (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM EVE (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM JUDY (PREFERRED) ---- SAWING 2:00 PM - 9:00 PM BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM ALICE (NEUTRAL) FRIDAY ---- SAWING 9:00 AM - 4:00 PM DAVID (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM FRANK (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM GRACE (NEUTRAL) ---- SAWING 2:00 PM - 9:00 PM BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM HEIDI (NEUTRAL) SATURDAY ---- SAWING 7:30 AM - 2:30 PM CAROL (PREFERRED) ---- PAINTING 7:30 AM - 2:30 PM IVAN (PREFERRED) ---- SANDING 9:45 AM - 4:45 PM DAVID (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM FRANK (NEUTRAL) ---- SAWING 2:00 PM - 9:00 PM ALICE (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM BOB (NEUTRAL) SUMMARY -- ALICE benefit: 13.000 3 PREFERRED 2 NEUTRAL 0 DISFAVORED -- BOB benefit: 14.000 4 PREFERRED 1 NEUTRAL 0 DISFAVORED -- CAROL benefit: 9.000 3 PREFERRED 0 NEUTRAL 0 DISFAVORED -- DAVID benefit: 15.000 5 PREFERRED 0 NEUTRAL 0 DISFAVORED -- EVE benefit: 9.000 3 PREFERRED 0 NEUTRAL 0 DISFAVORED -- FRANK benefit: 13.000 3 PREFERRED 2 NEUTRAL 0 DISFAVORED -- GRACE benefit: 8.000 2 PREFERRED 1 NEUTRAL 0 DISFAVORED -- HEIDI benefit: 9.000 1 PREFERRED 3 NEUTRAL 0 DISFAVORED -- IVAN benefit: 12.000 4 PREFERRED 0 NEUTRAL 0 DISFAVORED -- JUDY benefit: 6.000 2 PREFERRED 0 NEUTRAL 0 DISFAVORED </pre> <p> So we have a solution! We have 108 total benefit points. But it looks a bit uneven: Judy only works 2 days, while some people work many more: David works 5 for instance. Why is that? I update the program with =human_annotate = 'JUDY'=, run it again, and it tells me more about Judy's preferences: </p> <pre class="example">Objective value: 108.00000000 Enumerated nodes: 0 Total iterations: 0 Time (CPU seconds): 0.01 Time (Wallclock seconds): 0.01 Option for printingOptions changed from normal to all Total time (CPU seconds): 0.01 (Wallclock seconds): 0.02 SUNDAY (JUDY OFF) ---- SANDING 9:00 AM - 4:00 PM (JUDY NEUTRAL) EVE (PREFERRED) ---- SAWING 9:00 AM - 4:00 PM (JUDY PREFERRED) IVAN (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM (JUDY PREFERRED) FRANK (PREFERRED) ---- PAINTING 11:00 AM - 6:00 PM (JUDY NEUTRAL) HEIDI (PREFERRED) ---- SAWING 12:00 PM - 7:00 PM (JUDY PREFERRED) ALICE (PREFERRED) ---- PAINTING 12:15 PM - 7:15 PM (JUDY NEUTRAL) CAROL (PREFERRED) MONDAY (JUDY OFF) ---- SAWING 9:00 AM - 4:00 PM (JUDY PREFERRED) DAVID (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM (JUDY NEUTRAL) IVAN (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM (JUDY NEUTRAL) GRACE (PREFERRED) ---- SAWING 2:00 PM - 9:00 PM (JUDY DISFAVORED) ALICE (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM (JUDY DISFAVORED) HEIDI (NEUTRAL) TUESDAY (JUDY OFF) ---- SAWING 9:00 AM - 4:00 PM (JUDY PREFERRED) DAVID (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM (JUDY PREFERRED) EVE (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM (JUDY REFUSED) FRANK (NEUTRAL) ---- SAWING 2:00 PM - 9:00 PM (JUDY REFUSED) BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM (JUDY REFUSED) HEIDI (NEUTRAL) WEDNESDAY (JUDY SCHEDULED) ---- SAWING 7:30 AM - 2:30 PM (JUDY REFUSED) DAVID (PREFERRED) ---- PAINTING 7:30 AM - 2:30 PM (JUDY REFUSED) IVAN (PREFERRED) ---- SANDING 9:45 AM - 4:45 PM (JUDY NEUTRAL) FRANK (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM (JUDY PREFERRED) JUDY (PREFERRED) ---- SAWING 2:00 PM - 9:00 PM (JUDY DISFAVORED) BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM (JUDY DISFAVORED) ALICE (NEUTRAL) THURSDAY (JUDY SCHEDULED) ---- SANDING 9:00 AM - 4:00 PM (JUDY PREFERRED) GRACE (PREFERRED) ---- SAWING 9:00 AM - 4:00 PM (JUDY PREFERRED) CAROL (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM (JUDY PREFERRED) EVE (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM (JUDY PREFERRED) JUDY (PREFERRED) ---- SAWING 2:00 PM - 9:00 PM (JUDY DISFAVORED) BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM (JUDY DISFAVORED) ALICE (NEUTRAL) FRIDAY (JUDY OFF) ---- SAWING 9:00 AM - 4:00 PM (JUDY DISFAVORED) DAVID (PREFERRED) ---- PAINTING 9:45 AM - 4:45 PM (JUDY DISFAVORED) FRANK (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM (JUDY DISFAVORED) GRACE (NEUTRAL) ---- SAWING 2:00 PM - 9:00 PM (JUDY REFUSED) BOB (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM (JUDY REFUSED) HEIDI (NEUTRAL) SATURDAY (JUDY OFF) ---- SAWING 7:30 AM - 2:30 PM (JUDY REFUSED) CAROL (PREFERRED) ---- PAINTING 7:30 AM - 2:30 PM (JUDY REFUSED) IVAN (PREFERRED) ---- SANDING 9:45 AM - 4:45 PM (JUDY REFUSED) DAVID (PREFERRED) ---- PAINTING 12:00 PM - 7:00 PM (JUDY DISFAVORED) FRANK (NEUTRAL) ---- SAWING 2:00 PM - 9:00 PM (JUDY DISFAVORED) ALICE (PREFERRED) ---- PAINTING 2:00 PM - 9:00 PM (JUDY DISFAVORED) BOB (NEUTRAL) SUMMARY -- ALICE benefit: 13.000 3 PREFERRED 2 NEUTRAL 0 DISFAVORED -- BOB benefit: 14.000 4 PREFERRED 1 NEUTRAL 0 DISFAVORED -- CAROL benefit: 9.000 3 PREFERRED 0 NEUTRAL 0 DISFAVORED -- DAVID benefit: 15.000 5 PREFERRED 0 NEUTRAL 0 DISFAVORED -- EVE benefit: 9.000 3 PREFERRED 0 NEUTRAL 0 DISFAVORED -- FRANK benefit: 13.000 3 PREFERRED 2 NEUTRAL 0 DISFAVORED -- GRACE benefit: 8.000 2 PREFERRED 1 NEUTRAL 0 DISFAVORED -- HEIDI benefit: 9.000 1 PREFERRED 3 NEUTRAL 0 DISFAVORED -- IVAN benefit: 12.000 4 PREFERRED 0 NEUTRAL 0 DISFAVORED -- JUDY benefit: 6.000 2 PREFERRED 0 NEUTRAL 0 DISFAVORED </pre> <p> This tells us that on Monday Judy does not work, although she marked the SAWING shift as PREFERRED. Instead David got that shift. What would happen if David gave that shift to Judy? He would lose 3 points, she would gain 3 points, and the total would remain exactly the same at 108. </p> <p> How would we favor a more even distribution? We need some sort of tie-break. I want to add a nonlinearity to strongly disfavor people getting a low number of shifts. But PuLP is very explicitly a <i>linear</i> programming solver, and cannot solve nonlinear problems. Here we can get around this by enumerating each specific case, and assigning it a nonlinear benefit function. The most obvious approach is to define another set of boolean variables: <code>vars_Nshifts[human][N]</code>. And then using them to add extra benefit terms, with values nonlinearly related to <code>Nshifts</code>. Something like this: </p> <div class="org-src-container"> <pre class="src src-python"><span style="color: #cdcd00;">benefit_boost_Nshifts</span> = \ {2: -0.8, 3: -0.5, 4: -0.3, 5: -0.2} <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #cdcd00;">benefits</span>[h] = \ ... + \ pulp.lpSum([vars_Nshifts[h][n] * benefit_boost_Nshifts[n] \ <span style="color: #00cdcd; font-weight: bold;">for</span> n <span style="color: #00cdcd; font-weight: bold;">in</span> benefit_boost_Nshifts.keys()]) </pre> </div> <p> So in the previous example we considered giving David's 5th shift to Judy, for her 3rd shift. In that scenario, David's extra benefit would change from -0.2 to -0.3 (a shift of -0.1), while Judy's would change from -0.8 to -0.5 (a shift of +0.3). So the balancing out the shifts in this way would work: the solver would favor the solution with the higher benefit function. </p> <p> Great. In order for this to work, we need the <code>vars_Nshifts[human][N]</code> variables to function as intended: they need to be binary indicators of whether a specific person has that many shifts or not. That would need to be implemented with constraints. Let's plot it like this: </p> <div class="org-src-container"> <pre class="src src-python"><span style="color: #cdcd00;">#</span><span style="color: #cdcd00;">!/usr/bin/python3</span> <span style="color: #00cdcd; font-weight: bold;">import</span> numpy <span style="color: #00cdcd; font-weight: bold;">as</span> np <span style="color: #00cdcd; font-weight: bold;">import</span> gnuplotlib <span style="color: #00cdcd; font-weight: bold;">as</span> gp <span style="color: #cdcd00;">Nshifts_eq</span> = 4 <span style="color: #cdcd00;">Nshifts_max</span> = 10 <span style="color: #cdcd00;">Nshifts</span> = np.arange(Nshifts_max+1) <span style="color: #cdcd00;">i0</span> = np.nonzero(Nshifts != Nshifts_eq)[0] <span style="color: #cdcd00;">i1</span> = np.nonzero(Nshifts == Nshifts_eq)[0] gp.plot( <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">True value: var_Nshifts4==0, Nshifts!=4</span> ( np.zeros(i0.shape), Nshifts[i0], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "red"'</span>) ), <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">True value: var_Nshifts4==1, Nshifts==4</span> ( np.ones(i1.shape), Nshifts[i1], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "red"'</span>) ), <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">False value: var_Nshifts4==1, Nshifts!=4</span> ( np.ones(i0.shape), Nshifts[i0], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "black"'</span>) ), <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">False value: var_Nshifts4==0, Nshifts==4</span> ( np.zeros(i1.shape), Nshifts[i1], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "black"'</span>) ), unset=(<span style="color: #00cd00;">'grid'</span>), _set = (f<span style="color: #00cd00;">'xtics ("(Nshifts=={Nshifts_eq}) == 0" 0, "(Nshifts=={Nshifts_eq}) == 1" 1)'</span>), _xrange = (-0.1, 1.1), ylabel = <span style="color: #00cd00;">"Nshifts"</span>, title = <span style="color: #00cd00;">"Nshifts equality variable: not linearly separable"</span>, hardcopy = <span style="color: #00cd00;">"/tmp/scheduling-Nshifts-eq.svg"</span>) </pre> </div> <div class="figure"> <p><img alt="scheduling-Nshifts-eq.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/05_shop-scheduling-with-pulp/scheduling-Nshifts-eq.svg" width="80%" /> </p> </div> <p> So a hypothetical <code>vars_Nshifts[h][4]</code> variable (plotted on the x axis of this plot) would need to be defined by a set of linear AND constraints to <a href="https://en.wikipedia.org/wiki/Linear_separability">linearly separate</a> the true (red) values of this variable from the false (black) values. As can be seen in this plot, this isn't possible. So this representation does <i>not</i> work. </p> <p> How do we fix it? We can use inequality variables instead. I define a different set of variables <code>vars_Nshifts_leq[human][N]</code> that are 1 iff <code>Nshifts</code> <= <code>N</code>. The equality variable from before can be expressed as a difference of these inequality variables: <code>vars_Nshifts[human][N] = vars_Nshifts_leq[human][N]-vars_Nshifts_leq[human][N-1]</code> </p> <p> Can these <code>vars_Nshifts_leq</code> variables be defined by a set of linear AND constraints? Yes: </p> <div class="org-src-container"> <pre class="src src-python"><span style="color: #cdcd00;">#</span><span style="color: #cdcd00;">!/usr/bin/python3</span> <span style="color: #00cdcd; font-weight: bold;">import</span> numpy <span style="color: #00cdcd; font-weight: bold;">as</span> np <span style="color: #00cdcd; font-weight: bold;">import</span> numpysane <span style="color: #00cdcd; font-weight: bold;">as</span> nps <span style="color: #00cdcd; font-weight: bold;">import</span> gnuplotlib <span style="color: #00cdcd; font-weight: bold;">as</span> gp <span style="color: #cdcd00;">Nshifts_leq</span> = 4 <span style="color: #cdcd00;">Nshifts_max</span> = 10 <span style="color: #cdcd00;">Nshifts</span> = np.arange(Nshifts_max+1) <span style="color: #cdcd00;">i0</span> = np.nonzero(Nshifts > Nshifts_leq)[0] <span style="color: #cdcd00;">i1</span> = np.nonzero(Nshifts <= Nshifts_leq)[0] <span style="color: #00cdcd; font-weight: bold;">def</span> <span style="color: #0000ee; font-weight: bold;">linear_slope_yintercept</span>(xy0,xy1): <span style="color: #cdcd00;">m</span> = (xy1[1] - xy0[1])/(xy1[0] - xy0[0]) <span style="color: #cdcd00;">b</span> = xy1[1] - m * xy1[0] <span style="color: #00cdcd; font-weight: bold;">return</span> np.array(( m, b )) <span style="color: #cdcd00;">x01</span> = np.arange(2) <span style="color: #cdcd00;">x01_one</span> = nps.glue( nps.transpose(x01), np.ones((2,1)), axis=-1) <span style="color: #cdcd00;">y_lowerbound</span> = nps.inner(x01_one, linear_slope_yintercept( np.array((0, Nshifts_leq+1)), np.array((1, 0)) )) <span style="color: #cdcd00;">y_upperbound</span> = nps.inner(x01_one, linear_slope_yintercept( np.array((0, Nshifts_max)), np.array((1, Nshifts_leq)) )) <span style="color: #cdcd00;">y_lowerbound_check</span> = (1-x01) * (Nshifts_leq+1) <span style="color: #cdcd00;">y_upperbound_check</span> = Nshifts_max - x01*(Nshifts_max-Nshifts_leq) gp.plot( <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">True value: var_Nshifts_leq4==0, Nshifts>4</span> ( np.zeros(i0.shape), Nshifts[i0], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "red"'</span>) ), <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">True value: var_Nshifts_leq4==1, Nshifts<=4</span> ( np.ones(i1.shape), Nshifts[i1], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "red"'</span>) ), <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">False value: var_Nshifts_leq4==1, Nshifts>4</span> ( np.ones(i0.shape), Nshifts[i0], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "black"'</span>) ), <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">False value: var_Nshifts_leq4==0, Nshifts<=4</span> ( np.zeros(i1.shape), Nshifts[i1], <span style="color: #0000ee; font-weight: bold;">dict</span>(_with = <span style="color: #00cd00;">'points pt 7 ps 1 lc "black"'</span>) ), ( x01, y_lowerbound, y_upperbound, <span style="color: #0000ee; font-weight: bold;">dict</span>( _with = <span style="color: #00cd00;">'filledcurves lc "green"'</span>, tuplesize = 3) ), ( x01, nps.cat(y_lowerbound_check, y_upperbound_check), <span style="color: #0000ee; font-weight: bold;">dict</span>( _with = <span style="color: #00cd00;">'lines lc "green" lw 2'</span>, tuplesize = 2) ), unset=(<span style="color: #00cd00;">'grid'</span>), _set = (f<span style="color: #00cd00;">'xtics ("(Nshifts<={Nshifts_leq}) == 0" 0, "(Nshifts<={Nshifts_leq}) == 1" 1)'</span>, <span style="color: #00cd00;">'style fill transparent pattern 1'</span>), _xrange = (-0.1, 1.1), ylabel = <span style="color: #00cd00;">"Nshifts"</span>, title = <span style="color: #00cd00;">"Nshifts inequality variable: linearly separable"</span>, hardcopy = <span style="color: #00cd00;">"/tmp/scheduling-Nshifts-leq.svg"</span>) </pre> </div> <div class="figure"> <p><img alt="scheduling-Nshifts-leq.svg" src="https://notes.secretsauce.net/../../../notes/2025/03/05_shop-scheduling-with-pulp/scheduling-Nshifts-leq.svg" width="80%" /> </p> </div> <p> So we can use two linear constraints to make each of these variables work properly. To use these in the benefit function we can use the equality constraint expression from above, or we can use these directly: </p> <div class="org-src-container"> <pre class="src src-python"><span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">I want to favor people getting more extra shifts at the start to balance</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">things out: somebody getting one more shift on their pile shouldn't take</span> <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">shifts away from under-utilized people</span> <span style="color: #cdcd00;">benefit_boost_leq_bound</span> = \ {2: .2, 3: .3, 4: .4, 5: .5} <span style="color: #cdcd00;"># </span><span style="color: #cdcd00;">Constrain vars_Nshifts_leq variables to do the right thing</span> <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #00cdcd; font-weight: bold;">for</span> b <span style="color: #00cdcd; font-weight: bold;">in</span> benefit_boost_leq_bound.keys(): <span style="color: #cdcd00;">prob</span> += (pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys()]) >= (1 - vars_Nshifts_leq[h][b])*(b+1), f<span style="color: #00cd00;">"{h} at least {b} shifts: lower bound"</span>) <span style="color: #cdcd00;">prob</span> += (pulp.lpSum([<span style="color: #0000ee; font-weight: bold;">vars</span>[h][s] <span style="color: #00cdcd; font-weight: bold;">for</span> s <span style="color: #00cdcd; font-weight: bold;">in</span> shifts.keys()]) <= Nshifts_max - vars_Nshifts_leq[h][b]*(Nshifts_max-b), f<span style="color: #00cd00;">"{h} at least {b} shifts: upper bound"</span>) <span style="color: #cdcd00;">benefits</span> = <span style="color: #0000ee; font-weight: bold;">dict</span>() <span style="color: #00cdcd; font-weight: bold;">for</span> h <span style="color: #00cdcd; font-weight: bold;">in</span> humans: <span style="color: #cdcd00;">benefits</span>[h] = \ ... + \ pulp.lpSum([vars_Nshifts_leq[h][b] * benefit_boost_leq_bound[b] \ <span style="color: #00cdcd; font-weight: bold;">for</span> b <span style="color: #00cdcd; font-weight: bold;">in</span> benefit_boost_leq_bound.keys()]) </pre> </div> <p> In <i>this</i> scenario, David would get a boost of 0.4 from giving up his 5th shift, while Judy would lose a boost of 0.2 from getting her 3rd, for a net gain of 0.2 benefit points. The exact numbers will need to be adjusted on a case by case basis, but this works. </p> <p> The full program, with this and other extra features is available <a href="https://notes.secretsauce.net/../../../notes/2025/03/05_shop-scheduling-with-pulp/schedule.py">here</a>. </p> </div> <p class="date"> <a href="http://notes.secretsauce.net/notes/2025/03/05_shop-scheduling-with-pulp.html">05 March, 2025 12:02PM</a> by Dima Kogan </p> </div> </div> </div> <div class="channel"> <a href="https://optimizedbyotto.com/"> <img class="face" src="heads/otto.png" width="64" height="90" alt="hackergotchi for Otto Kekäläinen" /> </a> <h2 class="planet-title"> <a href="https://optimizedbyotto.com/" title="Optimized by Otto">Otto Kekäläinen</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://optimizedbyotto.com/post/distributed-social-media/_hide\" onClick=\"exclude( 'https://optimizedbyotto.com/post/distributed-social-media/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://optimizedbyotto.com/post/distributed-social-media/_show\" style=\"display:none;\" onClick=\"show( 'https://optimizedbyotto.com/post/distributed-social-media/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://optimizedbyotto.com/post/distributed-social-media/" class="https://optimizedbyotto.com/post/distributed-social-media/"> <div class="entry"> <h3 class="entry-title"> <a href="https://optimizedbyotto.com/post/distributed-social-media/">Will decentralized social media soon go mainstream?</a> </h3> <div class="content"> <img alt="Featured image of post Will decentralized social media soon go mainstream?" src="https://optimizedbyotto.com/post/distributed-social-media/featured-image.png" /><p>In today’s digital landscape, social media is more than just a communication tool — it is the primary medium for global discourse. Heads of state, corporate leaders and cultural influencers now broadcast their statements directly to the world, shaping public opinion in real time. However, the dominance of a few centralized platforms — X/Twitter, Facebook and YouTube — raises critical concerns about control, censorship and the monopolization of information. Those who control these networks effectively wield significant power over public discourse.</p> <p>In response, a new wave of distributed social media platforms has emerged, each built on different decentralized protocols designed to provide greater autonomy, censorship resistance and user control. While <a class="link" href="https://en.wikipedia.org/wiki/Comparison_of_software_and_protocols_for_distributed_social_networking" rel="noopener" target="_blank">Wikipedia maintains a comprehensive list</a> of distributed social networking software and protocols, it does not cover recent blockchain-based systems, nor does it highlight which have the most potential for mainstream adoption.</p> <p>This post explores the leading decentralized social media platforms and the protocols they are based on: <a class="link" href="https://joinmastodon.org/" rel="noopener" target="_blank">Mastodon</a> (ActivityPub), <a class="link" href="https://bsky.app/" rel="noopener" target="_blank">Bluesky</a> (AT Protocol), <a class="link" href="https://warpcast.com/" rel="noopener" target="_blank">Warpcast</a> (Farcaster), <a class="link" href="https://hey.xyz/" rel="noopener" target="_blank">Hey</a> (Lens) and <a class="link" href="https://primal.net/" rel="noopener" target="_blank">Primal</a> (Nostr).</p> <h2 id="comparison-of-architecture-and-mainstream-adoption-potential"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#comparison-of-architecture-and-mainstream-adoption-potential"></a>Comparison of architecture and mainstream adoption potential </h2><table> <thead> <tr> <th>Protocol</th> <th>Identity System</th> <th>Example</th> <th>Storage model</th> <th>Cost for end users</th> <th>Potential</th> </tr> </thead> <tbody> <tr> <td><strong>Mastodon</strong></td> <td>Tied to server domain</td> <td><a class="link" href="https://mastodon.social/@ottok" rel="noopener" target="_blank"><code>@ottok@mastodon.social</code></a></td> <td>Federated instances</td> <td>Free (some instances charge)</td> <td>High</td> </tr> <tr> <td><strong>Bluesky</strong></td> <td>Portable (DID)</td> <td><a class="link" href="https://bsky.app/profile/ottoke.bsky.social" rel="noopener" target="_blank"><code>ottoke.bsky.social</code></a></td> <td>Federated instances</td> <td>Free</td> <td>Moderate</td> </tr> <tr> <td><strong>Farcaster</strong></td> <td>ENS (Ethereum)</td> <td><a class="link" href="https://warpcast.com/ottok" rel="noopener" target="_blank"><code>@ottok</code></a></td> <td>Blockchain + off-chain</td> <td>Small gas fees</td> <td>Moderate</td> </tr> <tr> <td><strong>Lens</strong></td> <td>NFT-based (Polygon)</td> <td><a class="link" href="https://hey.xyz/u/ottok" rel="noopener" target="_blank"><code>@ottok</code></a></td> <td>Blockchain + off-chain</td> <td>Small gas fees</td> <td>Niche</td> </tr> <tr> <td><strong>Nostr</strong></td> <td>Cryptographic Keys</td> <td><a class="link" href="https://primal.net/p/npub16lc6uhqpg6dnqajylkhwuh3j7ynhcnje508tt4v6703w9kjlv9vqzz4z7f" rel="noopener" target="_blank"><code>npub16lc6uhqpg6dnqajylkhwuh3j7ynhcnje508tt4v6703w9kjlv9vqzz4z7f</code></a></td> <td>Federated instances</td> <td>Free (some instances charge)</td> <td>Niche</td> </tr> </tbody> </table> <h2 id="1-mastodon-activitypub"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#1-mastodon-activitypub"></a>1. Mastodon (ActivityPub) </h2><p><img alt="Screenshot of Mastodon" class="gallery-image" height="611" src="https://optimizedbyotto.com/post/distributed-social-media/mastodon-screenshot.png" width="800" /> </p> <p>Mastodon was created in 2016 by <a class="link" href="https://mastodon.social/@Gargron" rel="noopener" target="_blank">Eugen Rochko</a>, a German software developer who sought to provide a decentralized and user-controlled alternative to Twitter. It was built on the <a class="link" href="https://activitypub.rocks/" rel="noopener" target="_blank">ActivityPub protocol</a>, now standardized by W3C Social Web Working Group, to allow users to join independent servers while still communicating across the broader Mastodon network.</p> <p>Mastodon operates on a <em>federated model</em>, where multiple independently run servers communicate via ActivityPub. Each server sets its own moderation policies, leading to a decentralized but fragmented experience. The servers can alternatively be called instances, relays or nodes, depending on what vocabulary a protocol has standardized on.</p> <ul> <li><strong>Identity</strong>: User identity is tied to the instance where they registered, represented as <code>@username@instance.tld</code>.</li> <li><strong>Storage</strong>: Data is stored on individual instances, which federate messages to other instances based on their configurations.</li> <li><strong>Cost</strong>: Free to use, but relies on instance operators willing to run the servers.</li> </ul> <p>The protocol defines multiple activities such as:</p> <ul> <li>Creating a post</li> <li>Liking</li> <li>Sharing</li> <li>Following</li> <li>Commenting</li> </ul> <h3 id="example-message-in-activitypub-json-ld-format"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#example-message-in-activitypub-json-ld-format"></a>Example Message in ActivityPub (JSON-LD Format) </h3><div class="codeblock "> <header> <span class="codeblock-lang">json</span> <button class="codeblock-copy"> Copy </button> </header> <code id="codeblock-id-0" style="display: none;">{ "@context": "https://www.w3.org/ns/activitystreams", "type": "Create", "actor": "https://mastodon.social/users/ottok", "object": { "type": "Note", "content": "Hello from #Mastodon!", "published": "2025-03-03T12:00:00Z", "to": ["https://www.w3.org/ns/activitystreams#Public"] } }</code><div><div class="highlight"><pre tabindex="0"><code class="language-json"><span style="display: flex;"><span>{ </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"@context"</span>: <span style="color: #e6db74;">"https://www.w3.org/ns/activitystreams"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"type"</span>: <span style="color: #e6db74;">"Create"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"actor"</span>: <span style="color: #e6db74;">"https://mastodon.social/users/ottok"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"object"</span>: { </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"type"</span>: <span style="color: #e6db74;">"Note"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"content"</span>: <span style="color: #e6db74;">"Hello from #Mastodon!"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"published"</span>: <span style="color: #e6db74;">"2025-03-03T12:00:00Z"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"to"</span>: [<span style="color: #e6db74;">"https://www.w3.org/ns/activitystreams#Public"</span>] </span></span><span style="display: flex;"><span> } </span></span><span style="display: flex;"><span>}</span></span></code></pre></div></div></div> <p>Servers communicate across different platforms by publishing activities to their followers or forwarding activities between servers. Standard HTTPS is used between servers for communication, and the messages use JSON-LD for data representation. The <a class="link" href="https://en.wikipedia.org/wiki/WebFinger" rel="noopener" target="_blank">WebFinger protocol</a> is used for user discovery. There is however no neat way for home server discovery yet. This means that if you are browsing e.g. <a class="link" href="https://fosstodon.org/" rel="noopener" target="_blank">Fosstodon</a> and want to follow a user and press <em>Follow</em>, a dialog will pop up asking you to enter your own <em>home server</em> (e.g. <a class="link" href="https://mastodon.social/" rel="noopener" target="_blank">mastodon.social</a>) to redirect you there for actually executing the <em>Follow</em> action on with your account.</p> <p>Mastodon is open source under the <a class="link" href="https://en.wikipedia.org/wiki/GNU_Affero_General_Public_License" rel="noopener" target="_blank">AGPL</a> at <a class="link" href="https://github.com/mastodon/mastodon" rel="noopener" target="_blank">github.com/mastodon/mastodon</a>. Anyone can operate their own instance. It just requires to run your own server and some skills to maintain a Ruby on Rails app with a PostgreSQL database backend, and basic understanding of the protocol to configure federation with other ActivityPub instances.</p> <h3 id="popularity-already-established-but-will-it-grow-more"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#popularity-already-established-but-will-it-grow-more"></a>Popularity: Already established, but will it grow more? </h3><p>Mastodon has seen steady growth, especially after Twitter’s acquisition in 2022, with some estimates stating it peaked at 10 million users across thousands of instances. However, its fragmented user experience and the complexity of choosing instances have hindered mainstream adoption. Still, it remains the most established decentralized alternative to Twitter.</p> <p>Note that Donald Trump’s <a class="link" href="https://help.truthsocial.com/legal/open-source/" rel="noopener" target="_blank">Truth Social is based on the Mastodon software</a> but does not federate with the ActivityPub network.</p> <p>The ActivityPub protocol is the most widely used of its kind. One of the other most popular services is the <a class="link" href="https://join-lemmy.org/" rel="noopener" target="_blank">Lemmy</a> link sharing service, similar to Reddit. The larger ecosystem of ActivityPub is called <a class="link" href="https://en.wikipedia.org/wiki/Fediverse" rel="noopener" target="_blank">Fediverse</a>, and estimates put the <a class="link" href="https://www.fediverse.to/" rel="noopener" target="_blank">total active user count</a> around 6 million.</p> <h2 id="2-bluesky-at-protocol"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#2-bluesky-at-protocol"></a>2. Bluesky (AT Protocol) </h2><p><img alt="Screenshot of Bluesky" class="gallery-image" height="611" src="https://optimizedbyotto.com/post/distributed-social-media/bluesky-screenshot.png" width="800" /> </p> <p>Interestingly, <a class="link" href="https://bsky.app/" rel="noopener" target="_blank">Bluesky</a> was conceived within Twitter in 2019 by Twitter founder Jack Dorsey. After being incubated as a Twitter-funded project, it spun off as an independent Public Benefit LLC in February 2022 and launched its public beta in February 2023.</p> <p>Bluesky runs on top of the <strong>Authenticated Transfer (AT) Protocol</strong> published at <a class="link" href="https://github.com/bluesky-social/atproto" rel="noopener" target="_blank">https://github.com/bluesky-social/atproto</a>. The protocol enables portable identities and data ownership, meaning users can migrate between platforms while keeping their identity and content intact. In practice, however, there is only one popular server at the moment, which is Bluesky itself.</p> <ul> <li><strong>Identity</strong>: Usernames are domain-based (e.g., <code>@user.bsky.social</code>).</li> <li><strong>Storage</strong>: Content is theoretically federated among various servers.</li> <li><strong>Cost</strong>: Free to use, but relies on instance operators willing to run the servers.</li> </ul> <h3 id="example-message-in-at-protocol-json-format"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#example-message-in-at-protocol-json-format"></a>Example Message in AT Protocol (JSON Format) </h3><div class="codeblock "> <header> <span class="codeblock-lang">json</span> <button class="codeblock-copy"> Copy </button> </header> <code id="codeblock-id-1" style="display: none;">{ "repo": "did:plc:ottoke.bsky.social", "collection": "app.bsky.feed.post", "record": { "$type": "app.bsky.feed.post", "text": "Hello from Bluesky!", "createdAt": "2025-03-03T12:00:00Z", "langs": ["en"] } }</code><div><div class="highlight"><pre tabindex="0"><code class="language-json"><span style="display: flex;"><span>{ </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"repo"</span>: <span style="color: #e6db74;">"did:plc:ottoke.bsky.social"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"collection"</span>: <span style="color: #e6db74;">"app.bsky.feed.post"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"record"</span>: { </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"$type"</span>: <span style="color: #e6db74;">"app.bsky.feed.post"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"text"</span>: <span style="color: #e6db74;">"Hello from Bluesky!"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"createdAt"</span>: <span style="color: #e6db74;">"2025-03-03T12:00:00Z"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"langs"</span>: [<span style="color: #e6db74;">"en"</span>] </span></span><span style="display: flex;"><span> } </span></span><span style="display: flex;"><span>}</span></span></code></pre></div></div></div> <h3 id="popularity-hybrid-approach-may-have-business-benefits"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#popularity-hybrid-approach-may-have-business-benefits"></a>Popularity: Hybrid approach may have business benefits? </h3><p>Bluesky reported over 3 million users by 2024, probably getting traction due to its Twitter-like interface and Jack Dorsey’s involvement. Its hybrid approach — decentralized identity with centralized components — could make it a strong candidate for mainstream adoption, assuming it can scale effectively.</p> <h2 id="3-warpcast-farcaster-network"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#3-warpcast-farcaster-network"></a>3. Warpcast (Farcaster Network) </h2><p>Farcaster was launched in 2021 by <a class="link" href="https://warpcast.com/dan" rel="noopener" target="_blank">Dan Romero</a> and <a class="link" href="https://warpcast.com/varunsrin" rel="noopener" target="_blank">Varun Srinivasan</a>, both former crypto exchange Coinbase executives, to create a decentralized but user-friendly social network. Built on the <a class="link" href="https://ethereum.org/" rel="noopener" target="_blank">Ethereum blockchain</a>, it could potentially offer a very attack-resistant communication medium.</p> <p>However, in my own testing, Farcaster does not seem to fully leverage what Ethereum could offer. First of all, there is no diversity in programs implementing the protocol as at the moment there is only <a class="link" href="https://warpcast.com/" rel="noopener" target="_blank">Warpcast</a>. In Warpcast the signup requires an initial 5 USD fee that is not payable in ETH, and users need to create a new wallet address on the <a class="link" href="https://en.wikipedia.org/w/index.php?title=Base_%28blockchain%29&redirect=no" rel="noopener" target="_blank">Ethereum layer 2 network Base</a> instead of simply reusing their existing Ethereum wallet address or <a class="link" href="https://ens.domains/" rel="noopener" target="_blank">ENS name</a>.</p> <p>Despite this, I can understand why Farcaster may have decided to start out like this. Having a single client program may be the best strategy initially. One of the <a class="link" href="https://matrix.org/" rel="noopener" target="_blank">decentralized chat protocol Matrix</a> founders, Matthew Hodgson, shared in <a class="link" href="https://fosdem.org/2025/schedule/event/fosdem-2025-6274-the-road-to-mainstream-matrix/" rel="noopener" target="_blank">his FOSDEM 2025</a> talk that he slightly regrets focusing too much on developing the protocol instead of making sure the app to use it is attractive to end users. So it may be sensible to ensure Warpcast gets popular first, before attempting to make the Farcaster protocol widely used.</p> <p>As a protocol Farcaster’s hybrid approach makes it more scalable than fully on-chain networks, giving it a higher chance of mainstream adoption if it integrates seamlessly with broader Web3 ecosystems.</p> <ul> <li><strong>Identity</strong>: ENS (Ethereum Name Service) domains are used as usernames.</li> <li><strong>Storage</strong>: Messages are stored in off-chain hubs, while identity is on-chain.</li> <li><strong>Cost</strong>: Users must pay gas fees for some operations but reading and posting messages is mostly free.</li> </ul> <h3 id="example-message-in-farcaster-json-format"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#example-message-in-farcaster-json-format"></a>Example Message in Farcaster (JSON Format) </h3><div class="codeblock "> <header> <span class="codeblock-lang">json</span> <button class="codeblock-copy"> Copy </button> </header> <code id="codeblock-id-2" style="display: none;">{ "fid": 766579, "username": "ottok", "custodyAddress": "0x127853e48be3870172baa4215d63b6d815d18f21", "connectedWallet": "0x3ebe43aa3ae5b891ca1577d9c49563c0cee8da88", "text": "Hello from Farcaster!", "publishedAt": 1709424000, "replyTo": null, "embeds": [] }</code><div><div class="highlight"><pre tabindex="0"><code class="language-json"><span style="display: flex;"><span>{ </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"fid"</span>: <span style="color: #ae81ff;">766579</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"username"</span>: <span style="color: #e6db74;">"ottok"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"custodyAddress"</span>: <span style="color: #e6db74;">"0x127853e48be3870172baa4215d63b6d815d18f21"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"connectedWallet"</span>: <span style="color: #e6db74;">"0x3ebe43aa3ae5b891ca1577d9c49563c0cee8da88"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"text"</span>: <span style="color: #e6db74;">"Hello from Farcaster!"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"publishedAt"</span>: <span style="color: #ae81ff;">1709424000</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"replyTo"</span>: <span style="color: #66d9ef;">null</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"embeds"</span>: [] </span></span><span style="display: flex;"><span>}</span></span></code></pre></div></div></div> <h3 id="popularity-decentralized-social-media--decentralized-payments-a-winning-combo"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#popularity-decentralized-social-media--decentralized-payments-a-winning-combo"></a>Popularity: Decentralized social media + decentralized payments a winning combo? </h3><p>Ethereum founder Vitalik Buterin (<a class="link" href="https://warpcast.com/vbuterin" rel="noopener" target="_blank">warpcast.com/vbuterin</a>) and many core developers are active on the platform. Warpcast, the main client for Farcaster, has seen increasing adoption, especially among Ethereum developers and Web3 enthusiasts. I too have an profile at <a class="link" href="https://warpcast.com/ottok" rel="noopener" target="_blank">warpcast.com/ottok</a>. However, the numbers are still very low and far from reaching network effects to really take off.</p> <p>Blockchain-based social media networks, particularly those built on Ethereum, are compelling because they leverage existing user wallets and persistent identities while enabling native payment functionality. When combined with decentralized content funding through micropayments, these blockchain-backed social networks could offer unique advantages that centralized platforms may find difficult to replicate, being decentralized both as a technical network and in a funding mechanism.</p> <h2 id="4-heyxyz-lens-network"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#4-heyxyz-lens-network"></a>4. Hey.xyz (Lens Network) </h2><p>The Lens Protocol was developed by decentralized finance (DeFi) team <a class="link" href="https://aave.com/" rel="noopener" target="_blank">Aave</a> and launched in May 2022 to provide a user-owned social media network. While initially built on <a class="link" href="https://polygon.technology/" rel="noopener" target="_blank">Polygon</a>, it has since launched its own Layer 2 network called the Lens Network in February 2024. Lens is currently the main competitor to Farcaster.</p> <p>Lens stores profile ownership and references on-chain, while content is stored on <a class="link" href="https://ipfs.tech/" rel="noopener" target="_blank">IPFS</a>/<a class="link" href="https://arweave.org/" rel="noopener" target="_blank">Arweave</a>, enabling composability with DeFi and NFTs.</p> <ul> <li><strong>Identity</strong>: Profile ownership is tied to NFTs on the Polygon blockchain.</li> <li><strong>Storage</strong>: Content is on-chain and integrates with IPFS/Arweave (like NFTs).</li> <li><strong>Cost</strong>: Users must pay gas fees for some operations but reading and posting messages is mostly free.</li> </ul> <h3 id="example-message-in-lens-json-format"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#example-message-in-lens-json-format"></a>Example Message in Lens (JSON Format) </h3><div class="codeblock "> <header> <span class="codeblock-lang">json</span> <button class="codeblock-copy"> Copy </button> </header> <code id="codeblock-id-3" style="display: none;">{ "profileId": "@ottok", "contentURI": "ar://QmExampleHash", "collectModule": "0x23b9467334bEb345aAa6fd1545538F3d54436e96", "referenceModule": "0x0000000000000000000000000000000000000000", "timestamp": 1709558400 }</code><div><div class="highlight"><pre tabindex="0"><code class="language-json"><span style="display: flex;"><span>{ </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"profileId"</span>: <span style="color: #e6db74;">"@ottok"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"contentURI"</span>: <span style="color: #e6db74;">"ar://QmExampleHash"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"collectModule"</span>: <span style="color: #e6db74;">"0x23b9467334bEb345aAa6fd1545538F3d54436e96"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"referenceModule"</span>: <span style="color: #e6db74;">"0x0000000000000000000000000000000000000000"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"timestamp"</span>: <span style="color: #ae81ff;">1709558400</span> </span></span><span style="display: flex;"><span>}</span></span></code></pre></div></div></div> <h3 id="popularity-probably-not-as-social-media-site-but-maybe-as-protocol"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#popularity-probably-not-as-social-media-site-but-maybe-as-protocol"></a>Popularity: Probably not as social media site, but maybe as protocol? </h3><p>The social media side of Lens is mainly the <a class="link" href="https://hey.xyz" rel="noopener" target="_blank">Hey.xyz</a> website, which seems to have fewer users than Warpcast, and is even further away from reaching critical mass for network effects. The Lens protocol however has a <a class="link" href="https://www.lens.xyz/docs" rel="noopener" target="_blank">lot of advanced features</a> and it may gain adoption as the building block for many Web3 apps.</p> <h2 id="5-primalnet-nostr-network"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#5-primalnet-nostr-network"></a>5. Primal.net (Nostr Network) </h2><p>Nostr (Notes and Other Stuff Transmitted by Relays) was conceptualized in 2020 by an anonymous developer known as <a class="link" href="https://fiatjaf.com/" rel="noopener" target="_blank">fiatjaf</a>. One of the primary design tenets was to be a censorship-resistant protocol and it is popular among Bitcoin enthusiasts, with Jack Dorsey being one of the public supporters. Unlike the Farcaster and Lens protocols, Nostr is not blockchain-based but just a network of relay servers for message distribution. If does however use public key cryptography for identities, similar to how wallets work in crypto.</p> <ul> <li><strong>Identity</strong>: Public-private key pairs define identity (with prefix <code>npub...</code>).</li> <li><strong>Storage</strong>: Content is federated among multiple servers, which in Nostr vocabulary are called <em>relays</em>.</li> <li><strong>Cost</strong>: No gas fees, but relies on relay operators willing to run the servers.</li> </ul> <h3 id="example-message-in-nostr-json-format"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#example-message-in-nostr-json-format"></a>Example Message in Nostr (JSON Format) </h3><div class="codeblock "> <header> <span class="codeblock-lang">json</span> <button class="codeblock-copy"> Copy </button> </header> <code id="codeblock-id-4" style="display: none;">{ "id": "note1xyz...", "pubkey": "npub1...", "kind": 1, "content": "Hello from Nostr!", "created_at": 1709558400, "tags": [], "sig": "sig1..." }</code><div><div class="highlight"><pre tabindex="0"><code class="language-json"><span style="display: flex;"><span>{ </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"id"</span>: <span style="color: #e6db74;">"note1xyz..."</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"pubkey"</span>: <span style="color: #e6db74;">"npub1..."</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"kind"</span>: <span style="color: #ae81ff;">1</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"content"</span>: <span style="color: #e6db74;">"Hello from Nostr!"</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"created_at"</span>: <span style="color: #ae81ff;">1709558400</span>, </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"tags"</span>: [], </span></span><span style="display: flex;"><span> <span style="color: #f92672;">"sig"</span>: <span style="color: #e6db74;">"sig1..."</span> </span></span><span style="display: flex;"><span>}</span></span></code></pre></div></div></div> <h3 id="popularity-if-jack-dorsey-and-bitcoiners-promote-it-enough"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#popularity-if-jack-dorsey-and-bitcoiners-promote-it-enough"></a>Popularity: If Jack Dorsey and Bitcoiners promote it enough? </h3><p>Primal.net as a web app is pretty solid, but it does not stand out much. While Jack Dorsey has shown support by donating $1.5 million to the protocol development in December 2021, its success likely depends on broader adoption by the Bitcoin community.</p> <h2 id="will-any-of-these-replace-xtwitter"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#will-any-of-these-replace-xtwitter"></a>Will any of these replace X/Twitter? </h2><p>As usage patterns vary, the statistics are not fully comparable, but this overview of the situation in March 2025 gives a decent overview.</p> <table> <thead> <tr> <th>Platform</th> <th>Total Accounts</th> <th>Active Users</th> <th>Growth Trend</th> </tr> </thead> <tbody> <tr> <td>Mastodon</td> <td><a class="link" href="https://mastodon-analytics.com/" rel="noopener" target="_blank">~10 million</a></td> <td><a class="link" href="https://mastodon-analytics.com/" rel="noopener" target="_blank">~1 million</a></td> <td>Steady</td> </tr> <tr> <td>Bluesky</td> <td><a class="link" href="https://bsky.jazco.dev/stats" rel="noopener" target="_blank">~33 million</a></td> <td><a class="link" href="https://bsky.jazco.dev/stats" rel="noopener" target="_blank">~1 million</a></td> <td>Steady</td> </tr> <tr> <td>Nostr</td> <td><a class="link" href="https://stats.nostr.band/" rel="noopener" target="_blank">~41 million</a></td> <td><a class="link" href="https://stats.nostr.band/" rel="noopener" target="_blank">~20 thousand</a></td> <td>Steady</td> </tr> <tr> <td>Farcaster</td> <td><a class="link" href="https://dune.com/pixelhack/farcaster" rel="noopener" target="_blank">~850 thousand</a></td> <td><a class="link" href="https://dune.com/moesalih/web3-social" rel="noopener" target="_blank">~50 thousand</a></td> <td>Flat</td> </tr> <tr> <td>Lens</td> <td><a class="link" href="https://testnet.lenscan.io/chart/total-accounts" rel="noopener" target="_blank">~140 thousand</a></td> <td><a class="link" href="https://dune.com/moesalih/web3-social" rel="noopener" target="_blank">~20 thousand</a></td> <td>Flat</td> </tr> </tbody> </table> <p>Mastodon and Bluesky have already reached millions of users, while Lens and Farcaster are growing within crypto communities. It is however clear that none of these are anywhere close to how popular X/Twitter is. In particular, Mastodon had a huge influx of users in the fall of 2022 when Twitter was acquired, but to challenge the incumbents the growth would need to significantly accelerate. <strong>We can all accelerate this development by embracing decentralized social media now alongside existing dominant platforms.</strong></p> <p>Who knows, given the right circumstances maybe <a class="link" href="https://x.com/elonmusk" rel="noopener" target="_blank">X.com leadership</a> decides to change the operating model and start federating contents to break out from a walled garden model. The likelyhood of such development would increase if decentralized networks get popular, and the encumbents feel they need to participate to not lose out.</p> <h2 id="past-and-future"><a class="header-anchor" href="https://optimizedbyotto.com/index.xml#past-and-future"></a>Past and future </h2><p>The idea of decentralized social media is not new. One early pioneer identi.ca launched in 2008, only two years after Twitter, using the OStatus protocol to promote decentralization. A few years later it evolved into pump.io with the ActivityPump protocol, and also forked into GNU Social that continued with OStatus. I remember when these happened, and that in 2010 also Diaspora launched with fairly large publicity. Surprisingly both of these still operate (I can still post both on <a class="link" href="https://identi.ca/otto" rel="noopener" target="_blank">identi.ca</a> and <a class="link" href="https://diasp.org/people/4d1b3973ec26e266b50005e7" rel="noopener" target="_blank">diasp.org</a>), but the activity fizzled out years ago. <strong>The protocol however survived partially and evolved into ActivityPub, which is now the backbone of the Fediverse.</strong></p> <p>The evolution of decentralized social media over the next decade will likely parallel developments in democracy, freedom of speech and public discourse. While the early 2010s emphasized maximum independence and freedom, the late 2010s saw growing support for content moderation to combat misinformation. The AI era introduces new challenges, potentially requiring proof-of-humanity verification for content authenticity.</p> <p>Key factors that will determine success:</p> <ul> <li>User experience and ease of onboarding</li> <li>Network effects and critical mass of users</li> <li>Integration with existing web3 infrastructure</li> <li>Balance between decentralization and usability</li> <li>Sustainable economic models for infrastructure</li> </ul> <p>This is clearly an area of development worth monitoring closely, as the next few years may determine which protocol becomes the de facto standard for decentralized social communication.</p> </div> <p class="date"> <a href="https://optimizedbyotto.com/post/distributed-social-media/">05 March, 2025 12:00AM</a> </p> </div> </div> </div> <h1>March 04, 2025</h1> <div class="channel"> <a href="https://k3xec.com/"> <img class="face" src="heads/paultag.png" width="65" height="85" alt="hackergotchi for Paul Tagliamonte" /> </a> <h2 class="planet-title"> <a href="https://k3xec.com/" title="K3XEC">Paul Tagliamonte</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://k3xec.com/su68g/_hide\" onClick=\"exclude( 'https://k3xec.com/su68g/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://k3xec.com/su68g/_show\" style=\"display:none;\" onClick=\"show( 'https://k3xec.com/su68g/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://k3xec.com/su68g/" class="https://k3xec.com/su68g/"> <div class="entry"> <h3 class="entry-title"> <a href="https://k3xec.com/su68g/">Reverse Engineering (another) Restaurant Pager system 🍽️</a> </h3> <div class="content"> <p>Some of you may remember that I recently felt a bit underwhelmed by the last <a href="https://k3xec.com/td158/">pager</a> I reverse engineered – the Retekess TD-158, mostly due to how intuitive their design decions were. It was pretty easy to jump to conclusions because they had made some pretty good decisions on how to do things.</p> <p>I figured I’d spin the wheel again and try a new pager system – this time I went for a SU-68G-10 pager, since I recognized the form factor as another fairly common unit I’ve seen around town. Off to Amazon I went, bought a set, and got to work trying to track down the FCC filings on this model. I eventually found what seemed to be the right make/model, and it, once again, indicated that this system should be operating in the <code>433 MHz</code> ISM band likely using OOK modulation. So, figured I’d start with the center of the band (again) at <code>433.92 MHz</code>, take a capture, test my luck, and was greeted with a now very familiar sight.</p> <p><img alt="" src="https://k3xec.com/imgs/su68g/packet.png" /></p> <p>Same as the last goarounds, except the premable here is a <code>0</code> symbol followed by 6-ish symbol durations of no data, followed by 25 bits of a packet. Careful readers will observe 26 symbols above after the preamble – I did too! The last <code>0</code> in the screenshot above is not actually a part of the packet – rather, it’s part of the next packet’s preamble. Each packet is packed in pretty tight.</p> <h1 id="by-hand-demodulation">By Hand Demodulation</h1> <p>Going off the same premise as last time, I figured i’d give it a manual demod and see what shakes out (again). This is now the third time i’ve run this play, so check out either of my prior <a href="https://k3xec.com/christmas/">two</a> <a href="https://k3xec.com/td158/">posts</a> for a better written description of what’s going on here – I’ll skip all the details since i’d just be copy-pasting from those posts into here. Long story short, I demodulated a call for pager 1, call for pager 10, and a power off command.</p> <table> <thead> <tr> <td class="hz-1-6th">What</td> <td class="hz-5-6th">Bits</td> </tr> </thead> <tbody> <tr><td>Call 1 </td><td><code>1101111111100100100000000</code></td></tr> <tr><td>Call 10</td><td><code>1101111111100100010100000</code></td></tr> <tr><td>Off </td><td><code>1101111111100111101101110</code></td></tr> </tbody> </table> <p>A few things jump out at me here – the first 14 bits are fixed (in my case, <code>11011111111001</code>), which means some mix of preamble, system id, or other system-wide constant. Additionally, The last 9 bits also look like they are our pager – the <code>1</code> and <code>10</code> pager numbers (LSB bit order) jump right out (<code>100000000</code> and <code>010100000</code>, respectively). That just leaves the two remaining bits which look to be the “action” – <code>00</code> for a “Call”, and <code>11</code> for a “Power off”. I don’t super love this since command has two bits rather than one, the base station ID seems really long, and a 9-bit Pager ID is just weird. Also, what is up with that power-off pager id? Weird. So, let’s go and see what we can do to narrow down and confirm things by hand.</p> <h1 id="testing-bit-flips">Testing bit flips</h1> <p>Rather than call it a day at that, I figure it’s worth a bit of diligence to make sure it’s all correct – so I figured we should try sending packets to my pagers and see how they react to different messages after flipping bits in parts of the packet.</p> <p>I implemented a simple base station for the pagers using my Ettus B210mini, and threw together a simple OOK modulator and transmitter program which allows me to send specifically crafted test packets on frequency. Implementing the base station is pretty straightforward, because of the modulation of the signal (OOK), it’s mostly a matter of setting a buffer to <code>1</code> and <code>0</code> for where the carrier signal is on or off timed to the sample rate, and sending that off to the radio. If you’re interested in a more detailed writeup on the steps involved, there’s a bit more in my <a href="https://k3xec.com/christmas/">christmas tree post</a>.</p> <p>First off, I’d like to check the base id. I want to know if all the bits in what I’m calling the “base id” are truly part of the base station ID, or perhaps they have some other purpose (version, preamble?). I wound up following a three-step process for every base station id:</p> <ul> <li>Starting with an unmodified call packet for the pager under test: <ul> <li>Flip the Nth bit, and transmit the call. See if the pager reacts.</li> <li>Hold “SET”, and pair the pager with the new packet.</li> <li>Transmit the call. See if the pager reacts.</li> <li>After re-setting the ID, transmit the call with the physical base station, see if the pager reacts.</li> </ul> </li> <li>Starting with an unmodified off packet for the pager system</li> <li>Flip the Nth bit, transmit the off, see if the pager reacts.</li> </ul> <p>What wound up happening is that changing any bit in the first 14 bits meant that the packet no longer worked with any pager until it was re-paired, at which point it begun to work again. This likely means the first 14 bits are part of the base station ID – and not static between base stations, or some constant like a version or something. All bits appear to be used.</p> <p>I repeated the same process with the “command” bits, and found that only <code>11</code> and <code>00</code> caused the pagers to react for the pager ids i’ve tried.</p> <p>I repeated this process one last time with the “pager id” bits this time, and found the last bit in the packet isn’t part of the pager ID, and can be either a <code>1</code> or a <code>0</code> and still cause the pager to react as if it were a 0. This means that the last bit is unknown but it has no impact on either a power off or call, and all messages sent by my base station always have a 0 set. It’s not clear if this is used by anything – likely not since setting a bit there doesn’t result in any change of behavior I can see yet.</p> <h1 id="final-packet-structure">Final Packet Structure</h1> <p>After playing around with flipping bits and testing, the final structure I was able to come up with based on behavior I was able to observe from transmitting hand-crafted packets and watching pagers buzz:</p> <div class="hz-abi"> <div class="hz-abi-green hz-abi-2b" type="14 bits">base id</div> <div class="hz-abi-green hz-abi-2b" type="2 bits">command</div> <div class="hz-abi-green hz-abi-2b" type="8 bits">pager id</div> <div class="hz-abi-green hz-abi-2b" type="1 bit">???</div> </div> <h2 id="commands">Commands</h2> <p>The <code>command</code> section bit comes in two flavors – either a “call” or an “off” command.</p> <table> <thead> <tr> <td class="hz-1-6th">Type</td> <td class="hz-1-6th">Id (2 bits)</td> <td class="hz-4-6th">Description</td> </tr> </thead> <tbody> <tr><td>Call</td><td>00</td><td>Call the pager identified by the id in <code>pager id</code></td></tr> <tr><td>Off</td><td>11</td><td>Request pagers power off, <code>pager id</code> is always <code>10110111</code></td></tr> </tbody> </table> <p>As for the actual RF PHY characteristics, here’s my best guesses at what’s going on with them:</p> <table> <thead> <tr> <td class="hz-1-6th">What</td> <td class="hz-5-6th">Description</td> </tr> </thead> <tbody> <tr> <td>Center Frequency</td> <td>433.92 MHz</td> </tr> <tr> <td>Modulation</td> <td>OOK</td> </tr> <tr> <td>Symbol Duration</td> <td>1300us</td> </tr> <tr> <td>Bits</td> <td>25</td> </tr> <tr> <td>Preamble</td> <td>325us of carrier, followed by 8800us of no carrier</td> </tr> </tbody> </table> <p>I’m not 100% on the timings, but they appear to be close enough to work reliabily. Same with the center frequency, it’s roughly right but there may be a slight difference i’m missing.</p> <h1 id="lingering-questions">Lingering Questions</h1> <p>This was all generally pretty understandable – another system that had some good decisions, and wasn’t too bad to reverse engineer. This was a bit more fun to do, since there was a bit more ambiguity here, but still not crazy. At least this one was a bit more ambiguous that needed a bit of followup to confirm things, which made it a bit more fun.</p> <p>I am left with a few questions, though – which I’m kinda interested in understanding, but I’ll likely need a lot more data and/or original source:</p> <p>Why is the “command” two bits here? This was a bit tough to understand because of the number of bits they have at their disposal – given the one last bit at the end of the packet that doesn’t seem to do anything, there’s no reason this couldn’t have been a 16 bit base station id, and an 8 bit pager id along with a single bit command (call or off).</p> <p>When sending an “off” – why is power off that bit pattern? Other pager IDs don’t seem to work with “off”, so it has some meaning, but I’m not sure what that is. You press and hold 9 on the physical base station, but the code winds up coming out to <code>0xED</code>, <code>237</code> or maybe <code>-19</code> if it’s signed. I can’t quite figure out <em>why</em> it’s this value. Are there other codes?</p> <p>Finally – what’s up with the last bit? Why is it 25 bits and not 24? It must take more work to process something that isn’t 8 bit aligned – and all for something that’s not being used!</p> </div> <p class="date"> <a href="https://k3xec.com/su68g/">04 March, 2025 03:00PM</a> </p> </div> </div> </div> <h1>March 03, 2025</h1> <div class="channel"> <a href="https://bits.debian.org/"> <img class="face" src="heads/dwn.png" width="77" height="85" alt="hackergotchi for Bits from Debian" /> </a> <h2 class="planet-title"> <a href="https://bits.debian.org/" title="Bits from Debian">Bits from Debian</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://bits.debian.org/2025/03/bits-from-the-dpl-march.html_hide\" onClick=\"exclude( 'https://bits.debian.org/2025/03/bits-from-the-dpl-march.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://bits.debian.org/2025/03/bits-from-the-dpl-march.html_show\" style=\"display:none;\" onClick=\"show( 'https://bits.debian.org/2025/03/bits-from-the-dpl-march.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://bits.debian.org/2025/03/bits-from-the-dpl-march.html" class="https://bits.debian.org/2025/03/bits-from-the-dpl-march.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://bits.debian.org/2025/03/bits-from-the-dpl-march.html">Bits from the DPL</a> </h3> <div class="content"> <p>Dear Debian community,</p> <p>this is bits from DPL for February.</p> <h2>Ftpmaster team is seeking for new team members</h2> <p>In December, Scott Kitterman announced his retirement from the project. I personally regret this, as I vividly remember his invaluable support during the Debian Med sprint at the start of the COVID-19 pandemic. He even took time off to ensure new packages cleared the queue in under 24 hours. I want to take this opportunity to personally thank Scott for his contributions during that sprint and for all his work in Debian.</p> <p>With one fewer FTP assistant, I am concerned about the increased workload on the remaining team. I encourage anyone in the Debian community who is interested to consider reaching out to the FTP masters about joining their team.</p> <p>If you're wondering about the role of the <a href="https://ftp-master.debian.org/">FTP masters</a>, I'd like to share a fellow developer's perspective:</p> <blockquote> <p>"My read on the FTP masters is:</p> <blockquote> <ul> <li>In truth, they are the heart of the project.</li> <li>They know it.</li> <li>They do a fantastic job."</li> </ul> </blockquote> </blockquote> <p>I fully agree and see it as part of my role as DPL to ensure this remains true for Debian's future.</p> <p>If you're looking for a way to support Debian in a critical role where many developers will deeply appreciate your work, consider reaching out to the team. It's a great opportunity for any Debian Developer to contribute to a key part of the project.</p> <h2>Project Status: Six Months of Bug of the Day</h2> <p>In my Bits from the DPL talk at <a href="https://debconf24.debconf.org/talks/20-bits-from-the-dpl/">DebConf24</a>, I announced the Tiny Tasks effort, which I intended to start with a <a href="https://salsa.debian.org/qa/tiny_qa_tools/-/wikis/Tiny-QA-tasks#bug-of-the-day">Bug of the Day</a> project. Another idea was an Autopkgtest of the Day, but this has been postponed due to limited time resources-I cannot run both projects in parallel.</p> <p>The original goal was to provide small, time-bound examples for newcomers. To put it bluntly: in terms of attracting new contributors, it has been a failure so far. My offer to explain individual bug-fixing commits in detail, if needed, received no response, and despite my efforts to encourage questions, none were asked.</p> <p>However, the project has several positive aspects: experienced developers actively exchange ideas, collaborate on fixing bugs, assess whether packages are worth fixing or should be removed, and work together to find technical solutions for non-trivial problems.</p> <p>So far, the project has been engaging and rewarding every day, bringing new discoveries and challenges-not just technical, but also social. Fortunately, in the vast majority of cases, I receive positive responses and appreciation from maintainers. Even in the few instances where help was declined, it was encouraging to see that in two cases, maintainers used the ping as motivation to work on their packages themselves. This reflects the dedication and high standards of maintainers, whose work is essential to the project's success.</p> <p>I once used the metaphor that this project is like wandering through a dark basement with a lone flashlight-exploring aimlessly and discovering a wide variety of things that have accumulated over the years. Among them are true marvels with popcon >10,000, ingenious tools, and delightful games that I only recently learned about. There are also some packages whose time may have come to an end-but each of them reflects the dedication and effort of those who maintained them, and that deserves the utmost respect.</p> <p>Leaving aside the challenge of attracting newcomers, what have we achieved since August 1st last year?</p> <ul> <li>Fixed more than one package per day, typically addressing multiple bugs.</li> <li>Added and corrected numerous Homepage fields and watch files.</li> <li>The most frequently patched issue was "Fails To Cross-Build From Source" (all including patches).</li> <li>Migrated several packages from cdbs/debhelper to dh.</li> <li>Rewrote many d/copyright files to DEP5 format and thoroughly reviewed them.</li> <li>Integrated all affected packages into Salsa and enabled Salsa CI.</li> <li>Approximately half of the packages were moved to appropriate teams, while the rest are maintained within the Debian or Salvage teams.</li> <li>Regularly performed team uploads, ITS, NMUs, or QA uploads.</li> <li>Filed several RoQA bugs to propose package removals where appropriate.</li> <li>Reported multiple maintainers to the MIA team when necessary.</li> </ul> <p>With some goodwill, you can see a slight impact on the trends.debian.net <a href="https://trends.debian.net/">graphs</a> (thank you Lucas for the graphs), but I would never claim that this project alone is responsible for the progress. What I have also observed is the steady stream of daily uploads to the <a href="https://ftp-master.debian.org/deferred.html">delayed queue</a>, demonstrating the continuous efforts of many contributors. This ongoing work often remains unseen by most-including myself, if not for my regular check-ins on this list. I would like to extend my sincere thanks to everyone pushing fixes there, contributing to the overall quality and progress of Debian's QA efforts.</p> <p>If you examine the graphs for "Version Control System" and "VCS Hosting" with the goodwill mentioned above, you might notice a positive trend since mid-last year. The "Package Smells" category has also seen reductions in several areas: "no git", "no DEP5 copyright", "compat <9", and "not salsa". I'd also like to acknowledge the NMUers who have been working hard to address the "format != 3.0" issue. Thanks to all their efforts, this specific issue never surfaced in the Bug of the Day effort, but their contributions deserve recognition here.</p> <p>The experience I gathered in this project taught me a lot and inspired me to some followup we should discuss at a Sprint at DebCamp this year.</p> <p>Finally, if any newcomer finds this information interesting, I'd be happy to slow down and patiently explain individual steps as needed. All it takes is asking questions on the <a href="https://app.element.io/#/room/#debian-tiny-tasks:matrix.org">Matrix channel</a> to turn this into a "teaching by example" session.</p> <p>By the way, for newcomers who are interested, I used quite a few abbreviations-all of which are explained in the <a href="https://wiki.debian.org/Glossary">Debian Glossary</a>.</p> <h2>Sneak Peek at Upcoming Conferences</h2> <p>I will join two conferences in March-feel free to talk to me if you spot me there.</p> <ol> <li> <p>FOSSASIA Summit 2025 (March 13-15, Bangkok, Thailand) Schedule: <a href="https://eventyay.com/e/4c0e0c27/schedule">https://eventyay.com/e/4c0e0c27/schedule</a></p> </li> <li> <p>Chemnitzer Linux-Tage (March 22-23, Chemnitz, Germany) Schedule: <a href="https://chemnitzer.linux-tage.de/2025/de/programm/vortraege">https://chemnitzer.linux-tage.de/2025/de/programm/vortraege</a></p> </li> </ol> <p>Both events will have a Debian booth-come say hi!</p> <p>Kind regards Andreas.</p> </div> <p class="date"> <a href="https://bits.debian.org/2025/03/bits-from-the-dpl-march.html">03 March, 2025 11:00PM</a> by Andreas Tille </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="https://perezmeyer.com.ar/"> <img class="face" src="heads/lisandropm.png" width="78" height="100" alt="hackergotchi for Lisandro Damián Nicanor Pérez Meyer" /> </a> <h2 class="planet-title"> <a href="https://perezmeyer.com.ar/" title="Solo sé que se querer, que tengo Dios y tengo fe - planetdebian-en">Lisandro Damián Nicanor Pérez Meyer</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/_hide\" onClick=\"exclude( 'https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/_show\" style=\"display:none;\" onClick=\"show( 'https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/" class="https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/"> <div class="entry"> <h3 class="entry-title"> <a href="https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/">Going to Embedded World 2025 in Nuremberg</a> </h3> <div class="content"> <p>This year I'll be participating of <a href="https://www.embedded-world.de/en">Embedded World</a> 2025 in Nuremberg, representing the company I work for, <a href="https://www.ics.com/">ICS</a>. You will be able to find me at the <a href="https://www.automotivelinux.org/">Automotive Grade Linux</a> <a href="https://www.embedded-world.de/en/exhibitors-products/a/automotive-grade-linux-agl">booth on hall 4, 4-209</a>.</p> <p>If you are around be sure to come and say hi, and why not, exchange PGP/GPG keys!</p> </div> <p class="date"> <a href="https://perezmeyer.com.ar/blog/2025/03/03/going-to-embedded-world-2025/">03 March, 2025 01:44PM</a> by Lisandro Damián Nicanor Pérez Meyer </p> </div> </div> </div> <h1>March 02, 2025</h1> <div class="channel"> <div id="https://perezmeyer.com.ar/blog/2025/03/02/pgp-transition-6286a7d0-to-B48C1072/" class="https://perezmeyer.com.ar/blog/2025/03/02/pgp-transition-6286a7d0-to-B48C1072/"> <div class="entry"> <h3 class="entry-title"> <a href="https://perezmeyer.com.ar/blog/2025/03/02/pgp-transition-6286a7d0-to-B48C1072/">PGP/GPG transition from 0x6286A7D0 to 0xB48C1072</a> </h3> <div class="content"> <p>I am currently transitioning my GPG/GPG key from <a href="https://perezmeyer.com.ar/../../files/keys/6286A7D0-public.asc" title="GPG public key (D/4096 0x12DDFA84AC23B2BBF04B313CAB645F406286A7D0)">D/4096 0x12DDFA84AC23B2BBF04B313CAB645F406286A7D0</a> to <a href="https://perezmeyer.com.ar/../../files/keys/B48C1072-public.asc" title="GPG public key (D/4096 0xA94C9FBFA49AA7CD4F40BB9F5E9030CCB48C1072)">D/4096 0xA94C9FBFA49AA7CD4F40BB9F5E9030CCB48C1072</a>.</p> <p>Let's put this in plain text, signed with both keys:</p> <div class="highlight"><pre><span></span><code><span class="gh">-----BEGIN PGP SIGNED MESSAGE-----</span> <span class="na">Hash</span><span class="o">:</span><span class="w"> </span><span class="s">SHA512</span> <span class="na">- -----BEGIN PGP SIGNED MESSAGE-----</span> <span class="na">Hash</span><span class="o">:</span><span class="w"> </span><span class="s">SHA512</span> <span class="s">I</span><span class="w"> </span><span class="s">am</span><span class="w"> </span><span class="s">currently</span><span class="w"> </span><span class="s">transitioning</span><span class="w"> </span><span class="s">my</span><span class="w"> </span><span class="s">GPG/GPG</span><span class="w"> </span><span class="s">key</span><span class="w"> </span><span class="s">from</span><span class="w"> </span><span class="s">D/4096</span><span class="w"> </span><span class="s">0x12DDFA84AC23B2BBF04B313CAB645F406286A7D0</span><span class="w"> </span><span class="s">to</span><span class="w"> </span><span class="s">D/4096</span><span class="w"> </span><span class="s">0xA94C9FBFA49AA7CD4F40BB9F5E9030CCB48C1072.</span> <span class="s">This</span><span class="w"> </span><span class="s">file</span><span class="w"> </span><span class="s">is</span><span class="w"> </span><span class="s">first</span><span class="w"> </span><span class="s">signed</span><span class="w"> </span><span class="s">with</span><span class="w"> </span><span class="s">the</span><span class="w"> </span><span class="s">new</span><span class="w"> </span><span class="s">key</span><span class="w"> </span><span class="s">and</span><span class="w"> </span><span class="s">then</span><span class="w"> </span><span class="s">with</span><span class="w"> </span><span class="s">the</span><span class="w"> </span><span class="s">old</span><span class="w"> </span><span class="s">one.</span> <span class="s">-</span><span class="w"> </span><span class="s">-----BEGIN</span><span class="w"> </span><span class="s">PGP</span><span class="w"> </span><span class="s">SIGNATURE-----</span> <span class="s">iQIzBAEBCgAdFiEEqUyfv6Sap81PQLufXpAwzLSMEHIFAmfE6RwACgkQXpAwzLSM</span> <span class="s">EHJpUBAAwMAbOwGcRiuX/aBjqDMA9HerRgimNWE9xA35Asg3F+A5/AFrBo+BDng3</span> <span class="s">jviCGxR6YdicSLZptaScLuRnqG1i/OcochGDxvHYVQ9I/G9SuHB7ylqD7zDnO5pw</span> <span class="s">Lldwx9jovkszgXMC+vs1E9tQ4vpuWNQ1I7q90rdikywhvNdNs8XUSCUNCLol5fzm</span> <span class="s">u64hcKex3pwt7wYs6TxtgO5DLpp//5Z6NoZ5f/esC0837zqy5Py6+7scN3tgRmXj</span> <span class="s">SyALlhfOCsy4+v22K5xk0VNelEWUg+VKqgMjPYbEfGQ3e4LXId6gGlKF+OuXCJX5</span> <span class="s">Eqi2leO/O3c+1MZ8LMh3YQft1/TmYktASMTdwV7Y87qMgVkXsJqIvw8d9VNlZvET</span> <span class="s">B3MMsuPK9VNKCokbSiHwB2ZQR235Hq6LPrBfMPnoVb5QzUgIk8Kz92wM3NWVAjzE</span> <span class="s">oj/660SZ7SfbBi6qmQyMjYKSKN+kSZazQfoUZo0fK1Y1mywN/XkeeV+gq/ZiYPhI</span> <span class="s">QLbjEfoeHEVcufgQCU0PvUuKr/+ud8BAwdH/9YWxYnObAzXFxgOJ9AvDqKxbD+rw</span> <span class="s">MVXCU4xMtNHHDqgZ+pSdB0br/bYtIqh1YsFfHw16lUgj9lcmfnujhl+h700pob6d</span> <span class="s">oArO0Bjb0bM9PTRRAn3CMiz2UeerBzY6gvaSnO3oBQc/UAx3RgA=</span> <span class="s">=r9Sr</span> <span class="s">-</span><span class="w"> </span><span class="s">-----END</span><span class="w"> </span><span class="s">PGP</span><span class="w"> </span><span class="s">SIGNATURE-----</span> <span class="s">-----BEGIN</span><span class="w"> </span><span class="s">PGP</span><span class="w"> </span><span class="s">SIGNATURE-----</span> <span class="s">iQIzBAEBCgAdFiEEEt36hKwjsrvwSzE8q2RfQGKGp9AFAmfE6U8ACgkQq2RfQGKG</span> <span class="s">p9DEWA/+N1AtaPwVGRi3OTcC+mzjjVd3oB4H4E80559FCbWQLvbnlazCTgdVHxp5</span> <span class="s">Pjlm4I/hKYSaWNirUvE7Dq7LNWYYhZRBunXc/VrrX2fkxj99D+F9co5fXYO3fsQn</span> <span class="s">vlz1UZzq8OrvWJo5Cv65CkblQReB31SNY//gBk5SjaeL4bnH3qOLCn6gGrqIgkyj</span> <span class="s">qb8vQzk9ssb0b2P2hNJlkYQA20LUshyShyfnaAJuEtmDYp3F3fWfuyTPEznJZ0AJ</span> <span class="s">efxfkYqQIznY36Om8dW0ec5LI3Xb+Obj4ccfNhWBfVG4RKruKHEhQCDtZbMSGPDn</span> <span class="s">ns4yOl5cqbN/2Gqa/Ww+LafWPsa73NYQNDOIM2XhVFLf2wikGMnb2bew3iZrEBo5</span> <span class="s">BORucyd1sBFsdD2tXAZEaXBpuCU+7mI9bJz9Co2+NWf1+IDaKyvJSgl7cQxuUtd4</span> <span class="s">tp7mDB7Czf4yDK+QHqeWY46DtU0dlDpyOt2IijkJzhH6nL9cfo+W4JUFJrhd42Tr</span> <span class="s">fRqjt7WeGrauX+d8wfvVV/KFrCkuw51ojLAtztvH7iwDP85wAOu95AlT1kT4ZwlE</span> <span class="s">uEmdgtYE3GGwQKP2osndJZwic/tZuKrm7p5xFYJr8N95nsRNlk1ia4EkyvQbe49m</span> <span class="s">2+JHO8Q0EjUGfV2+bSw4Eupi6qEgWp2s4sIGpHEGzWYfNqmozWE=</span> <span class="s">=A5kI</span> <span class="gh">-----END PGP SIGNATURE-----</span> </code></pre></div> <p>The above can be found as a file <a href="https://perezmeyer.com.ar/../../files/keys/6286A7D0-to-B48C1072-transition.txt.asc.asc">here</a>.</p> </div> <p class="date"> <a href="https://perezmeyer.com.ar/blog/2025/03/02/pgp-transition-6286a7d0-to-B48C1072/">02 March, 2025 11:16PM</a> by Lisandro Damián Nicanor Pérez Meyer </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="https://www.earth.li/~noodles/blog/"> <img class="face" src="heads/noodles.png" width="100" height="108" alt="hackergotchi for Jonathan McDowell" /> </a> <h2 class="planet-title"> <a href="https://www.earth.li/~noodles/blog/" title="Noodles' Emptiness">Jonathan McDowell</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html_hide\" onClick=\"exclude( 'https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html_show\" style=\"display:none;\" onClick=\"show( 'https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html" class="https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html">RIP: Steve Langasek</a> </h3> <div class="content"> <p>[I’d like to stop writing posts like this. I’ve been trying to work out what to say now for nearly 2 months (writing the mail to <code class="language-plaintext highlighter-rouge">-private</code> to tell the <a href="https://www.debian.org/">Debian</a> project about his death is one of the hardest things I’ve had to write, and I bottled out and wrote something that was mostly just factual, because it wasn’t the place), and I’ve decided I just have to accept this won’t be the post I want it to be, but posted is better than languishing in drafts.]</p> <p>Last weekend I was in Portland, for the Celebration of Life of my friend Steve, who sadly passed away at the start of the year. It wasn’t entirely unexpected, but that doesn’t make it any easier.</p> <p>I’ve struggled to work out what to say about Steve. I’ve seen many touching comments from others in Debian about their work with him, but what that’s mostly brought home to me is that while I met Steve through Debian, he was first and foremost my friend rather than someone I worked with in Debian. And so everything I have to say is more about that friendship (and thus feels a bit self-centred).</p> <p>My first memory of Steve is getting lost with him in Porto Alegre, Brazil, during DebConf4. We’d decided to walk to a local mall to meet up with some other folk (I can’t recall how they were getting there, but it wasn’t walking), ended up deep in conversation (ISTR it was about shared library transititions), and then it took a bit longer than we expected. I don’t know how that managed to cement a friendship (neither of us saw it as the near death experience others feared we’d had), but it did.</p> <p>Unlike others I never texted Steve much; we’d occasionally chat on IRC, but nothing major. That didn’t seem to matter when we actually saw each other in person though, we just picked up like we’d seen each other the previous week. DebConf became a recurring theme of when we’d see each other. Even outside DebConf we <em>went</em> places together. The first time I went somewhere in the US that wasn’t the Bay Area, it was to Portland to see Steve. He, and his family, came to visit me in Belfast a couple of times, and I did road trip from Dublin to Cork with him. He took me to a <a href="https://www.usgs.gov/volcanoes/mount-st.-helens">volcano</a>.</p> <p>Steve saw injustice in the world and <em>actually tried to do something about it</em>. I still have a copy of the US constitution sitting on my desk that he gave me. He made me want to be a better person.</p> <p>The world is a worse place without him in it, and while I am better for having known him, I am sadder for the fact he’s gone.</p> </div> <p class="date"> <a href="https://www.earth.li/~noodles/blog/2025/03/fuck-cancer.html">02 March, 2025 04:56PM</a> </p> </div> </div> </div> <div class="channel"> <a href="https://www.chiark.greenend.org.uk/~cjwatson/blog/"> <img class="face" src="heads/cjwatson.png" width="70" height="82" alt="hackergotchi for Colin Watson" /> </a> <h2 class="planet-title"> <a href="https://www.chiark.greenend.org.uk/~cjwatson/blog/" title="Colin Watson's blog - planet-debian">Colin Watson</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html_hide\" onClick=\"exclude( 'https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html_show\" style=\"display:none;\" onClick=\"show( 'https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html" class="https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html">Free software activity in February 2025</a> </h3> <div class="content"> <p>Most of my Debian contributions this month were <a href="https://www.freexian.com/about/debian-contributions/">sponsored</a> by Freexian.</p> <p>You can also support my work directly via <a href="https://liberapay.com/cjwatson">Liberapay</a>.</p> <h2>OpenSSH</h2> <p>OpenSSH upstream released <a href="https://www.openssh.com/releasenotes.html#9.9p2">9.9p2</a> with fixes for <span class="caps">CVE</span>-2025-26465 and <span class="caps">CVE</span>-2025-26466. I got a heads-up on this in advance from the Debian security team, and prepared updates for all of testing/unstable, bookworm (Debian 12), bullseye (Debian 11), buster (Debian 10, <span class="caps">LTS</span>), and stretch (Debian 9, <span class="caps">ELTS</span>). jessie (Debian 8) is also still in <span class="caps">ELTS</span> for a few more months, but wasn’t affected by either vulnerability.</p> <p>Although I’m not particularly active in the Perl team, I fixed a <a href="https://bugs.debian.org/1096245">libnet-ssleay-perl build failure</a> because it was blocking openssl from migrating to testing, which in turn was blocking the above openssh fixes.</p> <p>I also sent a minor <a href="https://bugzilla.mindrot.org/show_bug.cgi?id=3788"><code>sshd -T</code> fix</a> upstream, simplified a number of autopkgtests using the newish <a href="https://bugs.debian.org/906424"><code>Restrictions: needs-sudo</code></a> facility, and prepared for <a href="https://bugs.debian.org/1098760">removing the obsolete <code>slogin</code> symlink</a>.</p> <h2>PuTTY</h2> <p>I upgraded to the <a href="https://www.chiark.greenend.org.uk/~sgtatham/putty/">new upstream version 0.83</a>.</p> <h2><span class="caps">GCC</span> 15 build failures</h2> <p>I fixed build failures with <a href="https://gcc.gnu.org/gcc-15/porting_to.html"><span class="caps">GCC</span> 15</a> in a few packages:</p> <ul> <li><a href="https://bugs.debian.org/1096829">icoutils</a> (<a href="https://savannah.nongnu.org/bugs/index.php?66812">contributed upstream</a>)</li> <li><a href="https://bugs.debian.org/1096891">kali</a></li> <li><a href="https://bugs.debian.org/1097550">parted</a></li> <li><a href="https://bugs.debian.org/1097681">python-setproctitle</a></li> <li><a href="https://bugs.debian.org/1098064">vigor</a></li> </ul> <h2>Python team</h2> <p>A lot of my Python team work is driven by its <a href="https://udd.debian.org/dmd/?email1=team%2Bpython%40tracker.debian.org&nosponsor1=on&email2=&email3=&packages=&ignpackages=&format=html&onlytesting=on">maintainer dashboard</a>. Now that we’ve finished the transition to Python 3.13 as the default version, and inspired by a recent <a href="https://lists.debian.org/debian-devel/2025/02/msg00134.html">debian-devel thread started by Santiago</a>, I thought it might be worth spending a bit of time on the “uscan error” section. <a href="https://wiki.debian.org/debian/watch"><code>uscan</code></a> is typically scraping upstream web sites to figure out whether new versions are available, and so it’s easy for its configuration to become outdated or broken. Most of this work is pretty boring, but it can often reveal situations where we didn’t even realize that a Debian package was out of date. I fixed these packages:</p> <ul> <li>cssutils (this in particular was very out of date due to a new and active upstream maintainer since 2021)</li> <li>django-assets</li> <li>django-celery-email</li> <li>django-sass</li> <li>django-yarnpkg</li> <li>json-tricks</li> <li>mercurial-extension-utils</li> <li>pydbus</li> <li>pydispatcher</li> <li>pylint-celery</li> <li>pyspread</li> <li>pytest-pretty</li> <li>python-apptools</li> <li>python-django-libsass (<a href="https://github.com/torchbox/django-libsass/pull/59">contributed a packaging fix upstream</a> in passing)</li> <li>python-django-postgres-extra</li> <li>python-django-waffle</li> <li>python-ephemeral-port-reserve</li> <li>python-ifaddr</li> <li>python-log-symbols</li> <li>python-msrest</li> <li>python-msrestazure</li> <li>python-netdisco</li> <li>python-pathtools</li> <li>python-user-agents</li> <li>sinntp</li> <li>wchartype</li> </ul> <p>I upgraded these packages to new upstream versions:</p> <ul> <li>cssutils (<a href="https://github.com/jaraco/cssutils/pull/62">contributed a packaging tweak upstream</a>)</li> <li>django-iconify</li> <li>django-sass</li> <li>domdf-python-tools</li> <li>extra-data (fixing a <a href="https://bugs.debian.org/1095343">numpy 2.0 failure</a>)</li> <li>flufl.i18n</li> <li>json-tricks</li> <li>jsonpickle</li> <li>mercurial-extension-utils</li> <li>mod-wsgi</li> <li>nbconvert</li> <li>orderly-set</li> <li>pydispatcher (<a href="https://github.com/mcfletch/pydispatcher/pull/9">contributed a Python 3.12 fix upstream</a>)</li> <li>pylint</li> <li>pytest-rerunfailures</li> <li>python-asyncssh</li> <li>python-box (<a href="https://github.com/cdgriffith/Box/pull/290">contributed a packaging fix upstream</a>)</li> <li>python-charset-normalizer</li> <li>python-django-constance</li> <li>python-django-guid</li> <li>python-django-pgtrigger</li> <li>python-django-waffle</li> <li>python-djangorestframework-simplejwt</li> <li>python-formencode</li> <li>python-holidays (<a href="https://github.com/vacanza/holidays/pull/2273">contributed a test fix upstream</a>)</li> <li>python-legacy-cgi</li> <li>python-marshmallow-polyfield (fixing a <a href="https://bugs.debian.org/1098600">test failure</a>)</li> <li>python-model-bakery</li> <li>python-mrcz (fixing a <a href="https://bugs.debian.org/1095373">numpy 2.0 failure</a>)</li> <li>python-netdisco</li> <li>python-npe2</li> <li>python-persistent</li> <li>python-pkginfo (fixing a <a href="https://bugs.debian.org/1098603">test failure</a>)</li> <li>python-proto-plus</li> <li>python-requests-ntlm</li> <li>python-roman</li> <li>python-semantic-release</li> <li>python-setproctitle</li> <li>python-stdlib-list</li> <li>python-trustme</li> <li>python-typeguard (fixing a <a href="https://bugs.debian.org/1098615">test failure</a>)</li> <li>python-tzlocal</li> <li>pyzmq</li> <li>setuptools-scm</li> <li>sqlfluff</li> <li>stravalib</li> <li>tomopy</li> <li>trove-classifiers</li> <li>xhtml2pdf (fixing <a href="https://bugs.debian.org/1084986"><span class="caps">CVE</span>-2024-25885</a>)</li> <li>xonsh</li> <li>zodbpickle</li> <li>zope.deprecation</li> <li>zope.testrunner</li> </ul> <p>In bookworm-backports, I updated python-django to 3:4.2.18-1 (issuing <a href="https://backports.debian.org/news/BSA-121_Security_Update_for_python-django/"><span class="caps">BSA</span>-121</a>) and added new backports of python-django-dynamic-fixture and python-django-pgtrigger, all of which are dependencies of <a href="https://freexian-team.pages.debian.net/debusine/">debusine</a>.</p> <p>I went through all the build failures related to python-click 8.2.0 (which was confusingly <a href="https://github.com/pallets/click/pull/2844">tagged but not fully released upstream</a> and posted an <a href="https://bugs.debian.org/1098507#17">analysis</a>.</p> <p>I fixed or helped to fix various other build/test failures:</p> <ul> <li><a href="https://bugs.debian.org/1095084">cython</a></li> <li><a href="https://bugs.debian.org/1095019">dask</a></li> <li><a href="https://bugs.debian.org/1095339">deepdish</a></li> <li><a href="https://bugs.debian.org/1094905">hickle</a> (<a href="https://github.com/telegraphic/hickle/pull/186">contributed upstream</a>)</li> <li><a href="https://bugs.debian.org/1095356">mdp</a> (<a href="https://github.com/mdp-toolkit/mdp-toolkit/pull/105">contributed upstream</a>)</li> <li><a href="https://bugs.debian.org/1098578">mypy</a></li> <li><a href="https://bugs.debian.org/1094040">pillow</a></li> <li><a href="https://bugs.debian.org/1098590">pynput</a></li> <li><a href="https://bugs.debian.org/1094085">python-fonticon-fontawesome6</a></li> <li><a href="https://bugs.debian.org/1098602">python-persistent</a> (<a href="https://github.com/zopefoundation/persistent/pull/214">contributed upstream</a>)</li> <li><a href="https://bugs.debian.org/1056874">python-srsly</a></li> </ul> <p>I <a href="https://github.com/zopefoundation/zope.testrunner/pull/192">dropped support for the old <code>setup.py ftest</code> command</a> from zope.testrunner upstream.</p> <p>I fixed various odds and ends of bugs:</p> <ul> <li><a href="https://bugs.debian.org/974455">django-memoize: autopkgtest must be marked superficial</a></li> <li><a href="https://bugs.debian.org/1035135">extra-data: extra-data: please add autopkgtests (to add coverage for python3-numpy)</a></li> <li><a href="https://bugs.debian.org/1094910">fpylll: missing dependency on numpy abi</a></li> <li><a href="https://bugs.debian.org/974492">python-box: autopkgtest must be marked superficial</a></li> <li><a href="https://bugs.debian.org/1095284">python-hdmedians: missing dependency on numpy abi</a></li> <li><a href="https://bugs.debian.org/1094317">python-legacy-cgi: missing requirement: openstack-pkg-tools</a></li> <li><a href="https://bugs.debian.org/1063372">python-tzlocal: doesn’t run any tests during the build or as autopkgtest</a></li> <li><a href="https://bugs.debian.org/1091503">requests: will <span class="caps">FTBFS</span> during trixie support period</a> (<a href="https://github.com/psf/requests/pull/6897">contributed supporting fix upstream</a>)</li> <li><a href="https://bugs.debian.org/1096004">setuptools-scm: project was renamed from <code>setuptools_scm</code> to <code>setuptools-scm</code></a></li> </ul> <h2>Installer team</h2> <p>Following up on <a href="https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-01.html">last month</a>, I merged and uploaded <a href="https://salsa.debian.org/installer-team/debian-installer-utils/-/merge_requests/11">Helmut’s <code>/usr</code>-move fix</a>.</p> </div> <p class="date"> <a href="https://www.chiark.greenend.org.uk/~cjwatson/blog/activity-2025-02.html">02 March, 2025 01:49PM</a> by Colin Watson </p> </div> </div> </div> <h1>March 01, 2025</h1> <div class="channel"> <a href="http://www.netfort.gr.jp/~dancer/diary/202503.html.en"> <img class="face" src="heads/dancer.png" width="75" height="97" alt="hackergotchi for Junichi Uekawa" /> </a> <h2 class="planet-title"> <a href="http://www.netfort.gr.jp/~dancer/diary/202503.html.en" title="Dancer's daily hackings">Junichi Uekawa</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58_hide\" onClick=\"exclude( 'http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58_show\" style=\"display:none;\" onClick=\"show( 'http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58" class="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58"> <div class="entry"> <h3 class="entry-title"> <a href="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58">Network is unreliable.</a> </h3> <div class="content"> Network is unreliable. Seems like my router is trying to reconnect every 20 seconds after something triggers. <p></p> </div> <p class="date"> <a href="http://www.netfort.gr.jp/~dancer/diary/daily/2025-Mar-2.html.en#2025-Mar-2-07:01:58">01 March, 2025 10:01PM</a> by Junichi Uekawa </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="https://debianbrasil.org.br/"> <img class="face" src="heads/debianbrasil.png" width="65" height="85" alt="hackergotchi for Debian Brasil" /> </a> <h2 class="planet-title"> <a href="https://debianbrasil.org.br/" title="Debian Brasil">Debian Brasil</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/_hide\" onClick=\"exclude( 'https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/_show\" style=\"display:none;\" onClick=\"show( 'https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/" class="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/"> <div class="entry"> <h3 class="entry-title"> <a href="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/">MiniDebConf Belo Horizonte 2024 - a brief report</a> </h3> <div class="content"> <hr /> <p>title: MiniDebConf Belo Horizonte 2024 - a brief report description: by Paulo Henrique de Lima Santana (phls) published: true date: 2025-03-01T17:40:50.904Z tags: blog, english editor: markdown</p> <h2>dateCreated: 2024-06-06T09:00:00.000Z</h2> <p>From April 27th to 30th, 2024, <a href="https://bh.mini.debconf.org/">MiniDebConf Belo Horizonte 2024</a> was held at the Pampulha Campus of <a href="https://ufmg.br">UFMG - Federal University of Minas Gerais</a>, in Belo Horizonte city.</p> <p><img alt="MiniDebConf BH 2024 banners" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-banners.jpg =400x" /> This was the fifth time that a MiniDebConf (as an exclusive in-person event about Debian) took place in Brazil. Previous editions were in Curitiba (<a href="https://br2016.mini.debconf.org/">2016</a>, <a href="https://br2017.mini.debconf.org">2017</a>, and <a href="https://br2018.mini.debconf.org">2018</a>), and in <a href="https://brasilia.mini.debconf.org">Brasília 2023</a>. We had other MiniDebConfs editions held within Free Software events such as <a href="http://fisl.org.br">FISL</a> and <a href="https://latinoware.org/">Latinoware</a>, and other online events. See our <a href="https://bh.mini.debconf.org/evento/edicoes-anteriores/">event history</a>.</p> <p>Parallel to MiniDebConf, on 27th (Saturday) <a href="https://flisol.info/FLISOL2024/Brasil">FLISOL - Latin American Free Software Installation Festival</a> took place. It's the largest event in Latin America to promote Free Software, and It has been held since 2005 simultaneously in several cities.</p> <p>MiniDebConf Belo Horizonte 2024 was a success (as were previous editions) thanks to the participation of everyone, regardless of their level of knowledge about Debian. We value the presence of both beginner users who are familiarizing themselves with the system and the official project developers. The spirit of welcome and collaboration was present during all the event.</p> <p><img alt="MiniDebConf BH 2024 flisol" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-flisol.jpg =400x" /> </p> <h2>2024 edition numbers</h2> <p>During the four days of the event, several activities took place for all levels of users and collaborators of the Debian project. The official schedule was composed of:</p> <ul> <li>06 rooms in parallel on Saturday;</li> <li>02 auditoriums in parallel on Monday and Tuesday;</li> <li>30 talks/BoFs of all levels;</li> <li>05 workshops for hands-on activities;</li> <li>09 lightning talks on general topics;</li> <li>01 Live Electronics performance with Free Software;</li> <li>Install fest to install Debian on attendees' laptops;</li> <li>BSP (Bug Squashing Party);</li> <li>Uploads of new or updated packages.</li> </ul> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-palestra-1.jpg =400x" /> The final numbers for MiniDebConf Belo Horizonte 2024 show that we had a record number of participants.</p> <ul> <li>Total people registered: 399</li> <li>Total attendees in the event: 224</li> </ul> <p>Of the 224 participants, 15 were official Brazilian contributors, 10 being DDs (Debian Developers) and 05 (Debian Maintainers), in addition to several unofficial contributors.</p> <p>The organization was carried out by 14 people who started working at the end of 2023, including Prof. Loïc Cerf from the Computing Department who made the event possible at UFMG, and 37 volunteers who helped during the event.</p> <p>As MiniDebConf was held at UFMG facilities, we had the help of more than 10 University employees.</p> <p>See the <a href="https://bh.mini.debconf.org/evento/organizadores/">list</a> with the names of people who helped in some way in organizing MiniDebConf Belo Horizonte 2024.</p> <p>The difference between the number of people registered and the number of attendees in the event is probably explained by the fact that there is no registration fee, so if the person decides not to go to the event, they will not suffer financial losses.</p> <p>The 2024 edition of MiniDebconf Belo Horizonte was truly grand and shows the result of the constant efforts made over the last few years to attract more contributors to the Debian community in Brazil. With each edition the numbers only increase, with more attendees, more activities, more rooms, and more sponsors/supporters.</p> <p><img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-grupo-1.jpg =400x" /> <br /> <br /> <img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-grupo-2.jpg =400x" /> </p> <h2>Activities</h2> <p>The MiniDebConf schedule was intense and diverse. On the 27th, 29th and 30th (Saturday, Monday and Tuesday) we had talks, discussions, workshops and many practical activities.</p> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-palestra-2.jpg =400x" /> On the 28th (Sunday), the Day Trip took place, a day dedicated to sightseeing around the city. In the morning we left the hotel and went, on a chartered bus, to the <a href="https://mercadocentral.com.br/">Belo Horizonte Central Market</a>. People took the opportunity to buy various things such as cheeses, sweets, cachaças and souvenirs, as well as tasting some local foods.</p> <p><img alt="MiniDebConf BH 2024 mercado" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-mercado.jpg =400x" /> After a 2-hour tour of the Market, we got back on the bus and hit the road for lunch at a typical Minas Gerais food restaurant.</p> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-restaurante.jpg =400x" /> With everyone well fed, we returned to Belo Horizonte to visit the city's main tourist attraction: Lagoa da Pampulha and Capela São Francisco de Assis, better known as <a href="http://portalbelohorizonte.com.br/o-que-fazer/arte-e-cultura/igrejas/igreja-sao-francisco-de-assis">Igrejinha da Pampulha</a>. <img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-igrejinha.jpg =400x" /> We went back to the hotel and the day ended in the hacker space that we set up in the events room for people to chat, packaging, and eat pizzas.</p> <p><img alt="MiniDebConf BH 2024 palestra" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-hotel.jpg =400x" /> </p> <h2>Crowdfunding</h2> <p>For the third time we ran a crowdfunding campaign and it was incredible how people contributed! The initial goal was to raise the amount equivalent to a gold tier of R$ 3,000.00. When we reached this goal, we defined a new one, equivalent to one gold tier + one silver tier (R$ 5,000.00). And again we achieved this goal. So we proposed as a final goal the value of a gold + silver + bronze tiers, which would be equivalent to R$ 6,000.00. The result was that we raised R$7,239.65 (~ USD 1,400) with the help of more than 100 people!</p> <p>Thank you very much to the people who contributed any amount. As a thank you, we <a href="https://bh.mini.debconf.org/doacoes/">list the names of the people who donated</a>. <img alt="MiniDebConf BH 2024 doadores" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-doadores.jpg =400x" /> </p> <h2>Food, accommodation and/or travel grants for participants</h2> <p>Each edition of MiniDebConf brought some innovation, or some different benefit for the attendees. In this year's edition in Belo Horizonte, as with DebConfs, we <a href="https://bh.mini.debconf.org/evento/bolsas/">offered bursaries for food, accommodation and/or travel</a> to help those people who would like to come to the event but who would need some kind of help.</p> <p>In the registration form, we included the option for the person to request a food, accommodation and/or travel bursary, but to do so, they would have to identify themselves as a contributor (official or unofficial) to Debian and write a justification for the request.</p> <p>Number of people benefited:</p> <ul> <li>Food: 69</li> <li>Accommodation: 20</li> <li>Travel: 18</li> </ul> <p>The food bursary provided lunch and dinner every day. The lunches included attendees who live in Belo Horizonte and the region. Dinners were paid for attendees who also received accommodation and/or travel. The accommodation was held at the <a href="https://www.bhjaraguahotel.com.br/">BH Jaraguá Hotel</a>. And the travels included airplane or bus tickets, or fuel (for those who came by car or motorbike).</p> <p>Much of the money to fund the bursaries came from the Debian Project, mainly for travels. We sent a budget request to the former Debian leader Jonathan Carter, and He promptly approved our request.</p> <p>In addition to this event budget, the leader also approved individual requests sent by some DDs who preferred to request directly from him.</p> <p>The experience of offering the bursaries was really good because it allowed several people to come from other cities.</p> <p><img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-jantar.jpg =400x" /> </p> <h2>Photos and videos</h2> <p>You can watch recordings of the talks at the links below:</p> <ul> <li><a href="https://www.youtube.com/playlist?list=PLU90bw3OpxLpu7hJO8TzySFX32_UD8Eh4">Youtube</a> - <a href="https://peertube.debian.social/w/p/3X7BY1MyH686QNCS2A6wkd">Peertube</a></li> <li><p><a href="https://meetings-archive.debian.net/pub/debian-meetings/2024/MiniDebConf-Belo-Horizonte/">video.debian.net</a> And see the photos taken by several collaborators in the links below:</p></li> <li><p><a href="https://photos.app.goo.gl/ZV14bZ9AQFaKsgio6">Google photos</a></p></li> <li><a href="https://cloud.debianbsb.org/s/wgzBtzKX2kbLCYP">Nextcloud</a></li> </ul> <h2>Thanks</h2> <p>We would like to thank all the attendees, organizers, volunteers, sponsors and supporters who contributed to the success of MiniDebConf Belo Horizonte 2024.</p> <p><img alt="MiniDebConf BH 2024 grupo" src="https://debianbrasil.org.br/blog/imagens/minidebconf-bh-2024-ate-2025.jpg =400x" /> </p> <h2>Sponsors</h2> <p><strong>Gold:</strong></p> <ul> <li><a href="https://www.collabora.com/">Collabora</a></li> </ul> <p><strong>Silver:</strong></p> <ul> <li><a href="https://jedai.ai/">Jedai.ai</a></li> <li><a href="https://www.toradex.com/pt-br">Toradex Brasil</a></li> <li><a href="https://www.globo.com">Globo.com</a></li> <li><a href="https://policorp.com.br">Policorp Tecnologia</a></li> </ul> <p><strong>Bronze:</strong></p> <ul> <li><a href="https://brdsoft.com.br/">BRDSoft - Tecnologias para TI e Telecomunicações</a></li> <li><p><a href="https://eita.coop.br/">EITA - Cooperativa de Trabalho Educação, Informação e Tecnologia para Autogestão</a> </p> <h2>Supporters</h2></li> <li><p><a href="https://ictl.org.br">ICTL - Instituto para Conservação de Tecnologias Livres</a> - <a href="https://www.nazinha.com.br/">Nazinha Alimentos</a></p></li> <li>DACOMPSI</li> </ul> <h2>Organizers</h2> <ul> <li><a href="https://www.debian.org/">Projeto Debian</a></li> <li><a href="https://debianbrasil.org.br/">Comunidade Debian Brasil</a></li> <li><a href="https://debian-minas-gerais.gitlab.io/site/">Comunidade Debian MG</a></li> <li><a href="https://dcc.ufmg.br/">DCC/UFMG - Departamento de Ciência da Computação da Universidade Federal de Minas Gerais</a> </li> </ul> </div> <p class="date"> <a href="https://debianbrasil.org.br/blog/minidebconf-bh-2024-a-brief-report/">01 March, 2025 05:40PM</a> </p> </div> </div> </div> <div class="channel"> <div id="https://debianbrasil.org.br/blog/debianday2024-santa-maria-report/" class="https://debianbrasil.org.br/blog/debianday2024-santa-maria-report/"> <div class="entry"> <h3 class="entry-title"> <a href="https://debianbrasil.org.br/blog/debianday2024-santa-maria-report/">Debian Day 2024 in Santa Maria - Brazil</a> </h3> <div class="content"> <p>by por Andrew Gonçalves</p> <p><a href="https://wiki.debian.org/DebianDay/2024/Brazil/SantaMaria">Debian Day in Santa Maria - RS 2024</a> was held after a 5-year hiatus from the previous version of the event. It took place on the morning of August 16, in the Blue Hall of the <a href="https://site.ufn.edu.br/">Franciscan University (UFN)</a> with support from the Debian community and the Computing Practices Laboratory of UFN.</p> <p>The event was attended by students from all semesters of the Computer Science, Digital Games and Informational Systems, where we had the opportunity to talk to the participants.</p> <p>Around 60 students attended a lecture introducing them to Free and Open Source Software, Linux and were introduced to the Debian project, both about the philosophy of the project and how it works in practice and the opportunities that have opened up for participants by being part of Debian.</p> <p>After the talk, a packaging demonstration was given by local DD Francisco Vilmar, who demonstrated in practice how software packaging works in Debian.</p> <p>I would like to thank all the people who helped us:</p> <ul> <li>Debian Project</li> <li>Professor Ana Paula Canal (UFN)</li> <li>Professor Sylvio André Garcia (UFN)</li> <li>Laboratory of Computing Practices</li> <li>Francisco Vilmar (local DD)</li> </ul> <p>And thanks to all the participants who attended this event asking intriguing questions and taking an interest in the world of Free Software.</p> <p>Photos:</p> <p><img alt="DD em Santa Maria 1" src="https://debianbrasil.org.br/blog/imagens/debianday-santa-maria-2024-1.jpg" width="400" /> <img alt="DD em Santa Maria 2" src="https://debianbrasil.org.br/blog/imagens/debianday-santa-maria-2024-2.jpg" width="400" /> <img alt="DD em Santa Maria 3" src="https://debianbrasil.org.br/blog/imagens/debianday-santa-maria-2024-3.jpg" width="400" /> <img alt="DD em Santa Maria 4" src="https://debianbrasil.org.br/blog/imagens/debianday-santa-maria-2024-4.jpg" width="400" /></p> </div> <p class="date"> <a href="https://debianbrasil.org.br/blog/debianday2024-santa-maria-report/">01 March, 2025 05:39PM</a> </p> </div> </div> </div> <div class="channel"> <div id="https://debianbrasil.org.br/blog/debianday2024-pouso-alegre-report/" class="https://debianbrasil.org.br/blog/debianday2024-pouso-alegre-report/"> <div class="entry"> <h3 class="entry-title"> <a href="https://debianbrasil.org.br/blog/debianday2024-pouso-alegre-report/">Debian Day 2024 in Pouso Alegre - Brazil</a> </h3> <div class="content"> <p>by <a href="https://contributors.debian.org/contributor/tico@salsa/">Thiago Pezzo</a> and <a href="https://contributors.debian.org/contributor/giovani/">Giovani Ferreira</a></p> <p>Local celebrations of <a href="https://wiki.debian.org/DebianDay/2024">Debian 2024 Day</a> also happened on [Pouso Alegre, MG, Brazil] (https://www.openstreetmap.org/relation/315431). In this year we managed to organize two days of lectures!</p> <p>On the 14th of August 2024, Wednesday morning, we were on the [Federal Institute of Education, Science and Technology of the South of Minas Gerais] (https://portal.ifsuldeminas.edu.br/index.php), (IFSULDEMINAS), Pouso Alegre campus. We did an introductory presentation of the <a href="https://wwww.debian.org">Project Debian</a>, operating system and community, for the three years of the Technical Course in Informatics (professional high school). The event was closed to IFSULDEMINAS students and talked to 60 people.</p> <p>On August 17th, 2024, a Saturday morning, we held the event open to the community at the <a href="https://www.uniivas.edu.br/">University of the Sapucaí Valley</a> (Univás), with institutional support of the Information Systems Course. We speak about the Debian Project with <a href="https://contributors.debian.org/contributor/giovani/">Giovani Ferreira</a> (Debian Developer); about the <a href="https://wiki.de.bi.org/Brazil/Translate/">Debian pt_BR translation team</a> with Thiago Pezzo; about everyday experiences using free software with Virginia Cardoso; and on how to set up a development environment ready for production using Debian and Docker with Marcos António dos Santos. After the lectures, snacks, coffee and cake were served, while the participants talked, asked questions and shared experiences.</p> <p>We would like to thank all the people who have helped us:</p> <ul> <li>Michelle Nery (IFSULDEMINAS) and André Martins (UNIVÁS) for the aid in the local organization - Paulo Santana (Debian Brazil) by the general organization</li> <li>Virginia Cardoso, Giovani Ferreira, Marco António and Thiago Pezzo for the lectures - And a special thanks to all of you who participated in our celebratio</li> </ul> <p>Some pictures from Pouso Alegre:</p> <p><img alt="Presentation at IFSULDEMINAS Pouso Alegre campus 1" src="https://debianbrasil.org.br/blog/imagens/debianday-pouso-alegre-2024-ifsuldeminas1.jpg" width="400" /> <img alt="Presentation at IFSULDEMINAS Pouso Alegre campus 2" src="https://debianbrasil.org.br/blog/imagens/debianday-pouso-alegre-2024-ifsuldeminas2.jpg" width="400" /> <img alt="Presentation at UNIVÁS Fátima campus 1" src="https://debianbrasil.org.br/blog/imagens/debianday-pouso-alegre-2024-univas1.jpg" width="400" /> <img alt="Presentation at UNIVÁS Fátima campus 2" src="https://debianbrasil.org.br/blog/imagens/debianday-pouso-alegre-2024-univas2.jpg" width="400" /> <img alt="Presentation at UNIVÁS Fátima campus 3" src="https://debianbrasil.org.br/blog/imagens/debianday-pouso-alegre-2024-univas3.jpg" width="400" /> <img alt="Presentation at UNIVÁS Fátima campus 4" src="https://debianbrasil.org.br/blog/imagens/debianday-pouso-alegre-2024-univas4.jpg" width="400" /> </p> </div> <p class="date"> <a href="https://debianbrasil.org.br/blog/debianday2024-pouso-alegre-report/">01 March, 2025 05:39PM</a> </p> </div> </div> </div> <div class="channel"> <div id="https://debianbrasil.org.br/blog/debianday-30-anos-sao-carlos-report/" class="https://debianbrasil.org.br/blog/debianday-30-anos-sao-carlos-report/"> <div class="entry"> <h3 class="entry-title"> <a href="https://debianbrasil.org.br/blog/debianday-30-anos-sao-carlos-report/">Debian Day 30 years in São Carlos - Brazil</a> </h3> <div class="content"> <p>This year's <a href="https://wiki.debian.org/DebianDay/">Debian day</a> was a pretty special one, we are celebrating 30 years! Giving the importance of this event, the Brazilian community planned a very special week. Instead of only local gatherings, we had a week of online talks streamed via Debian <a href="https://www.youtube.com/playlist?list=PLU90bw3OpxLoiEUdWm7uyTi71ATGk6oXm">Brazil's youtube channel</a> (soon the recordings will be uploaded to <a href="https://peertube.debian.social/w/p/r1gZyzq3anFaECh6QEmU4d">Debian's peertube instance)</a>. Nonetheless the local celebrations happened around the country and I've organized one in São Carlos with the help of <a href="https://gelos.club">GELOS</a>, the FLOSS group at <a href="https://www5.usp.br/">University of São Paulo</a>. The event happened on August 19th and went on the whole afternoon. We had some talks about Debian and free software (see table below), a coffee break where we had the chance to talk, and finished with a group photo (check this one and many others below). Actually, it wasn't the end, we carried on the conversation about Debian and free software in a local bar :-)</p> <p>We had around 30 people in the event and reached a greater audience via the announcements across the university's press releases and emails sent to our Brazilian mailing lists. You can check some of them below.</p> <ul> <li><a href="http://www.saocarlos.usp.br/evento-celebra-os-30-anos-de-um-projeto-que-revolucionou-o-mundo-do-software-livre/">Local campus press release</a> - <a href="https://www.icmc.usp.br/noticias/6242-evento-celebra-os-30-anos-de-um-projeto-que-revolucionou-o-mundo-do-software-livre">Computing institute press release</a> - <a href="https://eesc.usp.br/noticias/comunicados_s.php?guid=debian-day-30-anos-acontecera-na-usp-de-sao-carlos&termid=todos">Engineering institute press release</a> - <a href="https://scl.ifsp.edu.br/index.php/component/content/article/17-ultimas-noticias/2249-divulgacao-debian-day-30-anos-acontecera-na-usp-sao-carlos.html">Federal institute press release</a> - <a href="https://alioth-lists.debian.net/pipermail/debian-br-eventos/2023-August/000924.html">Debian-br-eventos email</a> Below you can check the list of talks.</li> </ul> <p>Time | Author | Title -----|--------|------ 14:10 | GELOS | Intro to GELOS 14:30 | Carlos Melara (Charles) | A ~~not so~~ Brief Introdution to the Debian Project 15:15 | Guilherme Paixão | Debian and the Free Culture 15:45 | zé | Free Software: the paths to a free life 16:15 | -- | Coffee Break 17:15 | Prof. Dr. Francisco José Monaco | The FOSS Ecosystem and You</p> <p>Here are some photos taken during the event!</p> <p><img alt="Preparation for Debian Day" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/getting-ready.jpg" width="400" /> Getting things ready for the event.</p> <p><img alt="Intro to GELOS" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/gelos-intro.jpg" width="400" /> Intro to GELOS talk.</p> <p><img alt="Debian intro" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/debian-intro.jpg" width="400" /> A ~~not so~~ Brief Introdution to the Debian Project talk.</p> <p><img alt="Everyone knows Debian" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/everyone-knows-debian.jpg" width="400" /> Everyone already knew Debian!</p> <p><img alt="Free software" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/free-culture.jpg" width="400" /> Debian and the Free Culture talk</p> <p><img alt="Auditorium" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/auditorium.jpg" width="400" /> People in the auditorium space. </p> <p><img alt="Free software" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/free-software.jpg" width="400" /> Free Software: the paths to a free life talk</p> <p><img alt="Coffee Break" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/coffee-break.jpg" width="400" /> Coffee Break.</p> <p><img alt="FOSS Ecosystem" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/foss-ecosystem.jpg" width="400" /> The FOSS Ecosystem and You talk.</p> <p><img alt="Group photo" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/group-photo.jpg" width="400" /> Group photo.</p> <p><img alt="Celebration afterwards" src="https://debianbrasil.org.br/blog/imagens/debian-day-30-anos/sao-carlos/bar.jpg" width="400" /> Celebration goes on in the bar.</p> </div> <p class="date"> <a href="https://debianbrasil.org.br/blog/debianday-30-anos-sao-carlos-report/">01 March, 2025 05:39PM</a> </p> </div> </div> </div> <div class="channel"> <a href="https://honk.sigxcpu.org/con/"> <img class="face" src="heads/agx.png" width="100" height="100" alt="hackergotchi for Guido Günther" /> </a> <h2 class="planet-title"> <a href="https://honk.sigxcpu.org/con/" title="Colors of Noise - Entries tagged planetdebian">Guido Günther</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html_hide\" onClick=\"exclude( 'https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html_show\" style=\"display:none;\" onClick=\"show( 'https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html" class="https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html"> <div class="entry"> <h3 class="entry-title"> <a href="https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html">Free Software Activities February 2025</a> </h3> <div class="content"> <p>Another short status update of what happened on my side last month. One larger blocks are the <a href="https://phosh.mobi/releases/rel-0.45.0/">Phosh 0.45</a> release, also reviews took a considerable amount of time. From the fun side debugging <a href="https://git.abscue.de/obp/bananui">bananui</a> and coming up with a fix in phoc as well as setting up a small GSM network using <a href="https://osmocom.org/">osmocom</a> to <a href="https://ruhr.social/@agx/114081727236437022">test more Cell Broadcast thingies</a> were likely the most fun parts.</p> <h2><a href="https://gitlab.gnome.org/World/Phosh/phosh">phosh</a></h2> <ul> <li>Release <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1627">0.45~beta1</a>, <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1640/diffs">0.45~rc1</a>, <a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/644">0.45.0</a></li> <li>Don't hide player when track is stopped (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1633">MR</a>) - helps with e.g. Shortwave</li> <li>Fetch cover art via http (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1634">MR</a>)</li> <li>Update CI images (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1639">MR</a>)</li> <li>Robustify symbol file generation (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests?state=merged">MR</a>)</li> <li>Handle cutouts in the indicators area (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1655">MR</a>)</li> <li>Reduce flicker when opening overview (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1657">MR</a>)</li> <li>Select less noisy default background (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1659">MR</a>)</li> </ul> <h2><a href="https://gitlab.gnome.org/World/Phosh/phoc">phoc</a></h2> <ul> <li>Release <a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/630">0.45~beta1</a>, <a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/638">0.45~rc1</a>, <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1642">0.45.0</a></li> <li>Add support for ext-foreign-toplevel-v1 (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/636">MR</a>)</li> <li>Keep wlroots-0.19.x in shape and add support for ext-image-copy-capture-v1 (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/599">MR</a>)</li> <li>Fix geometry with scale when rendering to a buffer (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/637">MR</a>)</li> <li>Allow to tweak log domains at runtime (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/639">MR</a>)</li> <li>Print more useful information on startup (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/641">MR</a>)</li> <li>Provide PID of toplevel for phosh (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/645">MR</a>)</li> <li>Improve detection for hardware keyboards (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/649">MR</a>) (mostly to help bananui)</li> <li>Make tests a bit more flexible (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/650/diffs">MR</a>)</li> <li>Use <code>wlr_damage_ring_rotate_buffer</code> (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/653/diffs">MR</a>). Another prep for 0.19.x.</li> <li>Support <code>wp-alpha-modifier-v1</code> protocol (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/656">MR</a>)</li> </ul> <h2><a href="https://gitlab.gnome.org/guidog/phosh-osk-stub">phosh-osk-stub</a></h2> <ul> <li>Release <a href="https://gitlab.gnome.org/guidog/phosh-osk-stub/-/merge_requests/186">0.45~rc1</a>, <a href="https://gitlab.gnome.org/guidog/phosh-osk-stub/-/merge_requests/187">0.45.0</a></li> </ul> <h2>phosh-tour</h2> <ul> <li>Release <a href="https://gitlab.gnome.org/World/Phosh/phosh-tour/-/merge_requests/45">0.45~rc1</a>, <a href="https://gitlab.gnome.org/World/Phosh/phosh-tour/-/merge_requests/48">0.45.0</a></li> <li>Maintenance (<a href="https://gitlab.gnome.org/World/Phosh/phosh-tour/-/merge_requests/46">MR</a>, <a href="https://gitlab.gnome.org/World/Phosh/phosh-tour/-/merge_requests/47">MR</a>)</li> </ul> <h2>phosh-mobile-settings</h2> <ul> <li>Release <a href="https://gitlab.gnome.org/World/Phosh/phosh-mobile-settings/-/merge_requests/182">0.45~rc1</a>, <a href="https://gitlab.gnome.org/World/Phosh/phosh-mobile-settings/-/merge_requests?scope=all&state=merged">0.45.0</a></li> </ul> <h2>pfs</h2> <ul> <li>Add common checks and check meson files (<a href="https://gitlab.gnome.org/guidog/pfs/-/merge_requests/11">MR</a>)</li> </ul> <h2>libphosh-rs</h2> <ul> <li>Update for libphosh <a href="https://gitlab.gnome.org/guidog/libphosh-rs/-/merge_requests/31">0.45</a></li> <li>Release <a href="https://gitlab.gnome.org/guidog/libphosh-rs/-/merge_requests/33">0.0.6</a></li> </ul> <h2>meta-phosh</h2> <ul> <li>Add common dot files and job to check meson formatting (<a href="https://gitlab.gnome.org/guidog/meta-phosh/-/merge_requests/22">MR</a>)</li> <li>Add l10n modules to string freeze announcement (based on suggestion by Alexandre Franke) (<a href="https://gitlab.gnome.org/guidog/meta-phosh/-/merge_requests/24">MR</a>)</li> <li>Bring over <code>mk-gitlab-rel</code> and improve it for alpha, beta, RCs (<a href="https://gitlab.gnome.org/guidog/meta-phosh/-/merge_requests/27">MR</a>)</li> </ul> <h2>libcmatrix</h2> <ul> <li>Release <a href="https://source.puri.sm/Librem5/libcmatrix/-/merge_requests/105">0.3.0</a></li> </ul> <h2>Debian</h2> <ul> <li>Upload phoc <a href="https://salsa.debian.org/DebianOnMobile-team/phoc/-/merge_requests/63">0.45~beta1</a>, <a href="https://salsa.debian.org/DebianOnMobile-team/phoc/-/merge_requests/64">0.45~rc1</a>, <a href="https://salsa.debian.org/DebianOnMobile-team/phosh/-/merge_requests/112">0.45.0</a></li> <li>Upload phosh <a href="https://salsa.debian.org/DebianOnMobile-team/phosh/-/merge_requests/107">0.45~beta1</a>, <a href="https://salsa.debian.org/DebianOnMobile-team/phosh/-/merge_requests/108">0.45~rc1</a>, <a href="https://salsa.debian.org/DebianOnMobile-team/phoc/-/merge_requests/65">0.45.0</a></li> <li>Uplaod feedbackd <a href="https://salsa.debian.org/DebianOnMobile-team/feedbackd/-/merge_requests/28">0.7.0</a></li> <li>Upload xdg-desktop-portal-phosh <a href="https://salsa.debian.org/DebianOnMobile-team/xdg-desktop-portal-phosh/-/merge_requests/4">0.45.0</a></li> <li>Upload phosh-tour <a href="https://salsa.debian.org/DebianOnMobile-team/phosh-tour/-/merge_requests/20">0.45~rc1</a>, <a href="https://salsa.debian.org/DebianOnMobile-team/phosh-tour/-/merge_requests/21">0.45.0</a></li> <li>Upload phosh-osk-stub <a href="https://salsa.debian.org/DebianOnMobile-team/phosh-osk-stub/-/merge_requests/30">0.45~rc1</a>, <a href="https://salsa.debian.org/DebianOnMobile-team/phosh-osk-stub/-/merge_requests/31">0.45.0</a></li> <li>Upload phosh-mobile-settings <a href="https://salsa.debian.org/DebianOnMobile-team/phosh-mobile-settings/-/merge_requests/41">0.45~rc1</a>, <a href="https://salsa.debian.org/DebianOnMobile-team/phosh-mobile-settings/-/merge_requests/42">0.45.0</a></li> <li>phosh: Fix dependencies of library dev package (<a href="https://salsa.debian.org/DebianOnMobile-team/phosh/-/merge_requests/109/diffs">MR</a>) (and add a test)</li> <li>Update libphosh-rs to 0.0.6 (<a href="https://salsa.debian.org/rust-team/debcargo-conf/-/merge_requests/841">MR</a>)</li> <li>Update iio-sensor-proxy to 3.6 (<a href="https://salsa.debian.org/debian/iio-sensor-proxy/-/merge_requests/9">MR</a>)</li> <li>Backport qbootctl RDONLY patch (<a href="https://salsa.debian.org/DebianOnMobile-team/qbootctl/-/merge_requests/5">MR</a>) to make generating the boot image more robust</li> <li>libssc: Update to 0.2.1 (<a href="https://salsa.debian.org/agx/libssc/-/merge_requests/1">MR</a>)</li> <li>dom-tools: Write errors to stderr (<a href="https://salsa.debian.org/DebianOnMobile-team/dom-tools/-/merge_requests/3">MR</a>)</li> <li>dom-tools: Use underscored version to drop the branch <code>~</code> (<a href="https://salsa.debian.org/DebianOnMobile-team/dom-tools/-/merge_requests/2">MR</a>)</li> <li>libmbim: Upload 1.31.6 to experimental (<a href="https://salsa.debian.org/DebianOnMobile-team/libmbim/-/merge_requests/11">MR</a>)</li> <li>ModemManager: Upload 1.23.12 to experimental (<a href="https://salsa.debian.org/DebianOnMobile-team/modemmanager/-/merge_requests/25">MR</a>)</li> </ul> <h2>gmobile</h2> <ul> <li>data: Add display-panel for Furilabs FLX1 (<a href="https://gitlab.gnome.org/World/Phosh/gmobile/-/merge_requests/60">MR</a>)</li> </ul> <h2>feedbackd</h2> <ul> <li>Release <a href="https://source.puri.sm/Librem5/feedbackd/-/merge_requests/152">0.7.0</a>)</li> </ul> <h2>grim</h2> <ul> <li>Allow to force screen capture protocol (<a href="https://lists.sr.ht/~emersion/grim-dev/patches/57325">MR</a>)</li> </ul> <h2>Wayland protocols</h2> <ul> <li>Address multiple rounds of review comments in the <code>xdg-occlusion</code> (now <code>xdg-cutouts</code>) protocol (<a href="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/372">MR</a>)</li> </ul> <h2>g4music</h2> <ul> <li>Set prefs parent (<a href="https://gitlab.gnome.org/neithern/g4music/-/merge_requests/45">MR</a>)</li> </ul> <h2>wlroots</h2> <ul> <li>Backport touch up fix to 0.18 (<a href="https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4985">MR</a>)</li> </ul> <h2>qbootctl</h2> <ul> <li>Don't recreate all partitions on read operations (<a href="https://github.com/linux-msm/qbootctl/pull/2">MR</a>)</li> </ul> <h2>bananui-shell</h2> <ul> <li>Check for keyboard caps before using them (<a href="https://github.com/agx/bananui-shell/commit/e0c052fa6db7823b9878c8c6377c1d03dc49c334">Patch</a>, <a href="https://git.abscue.de/obp/bananui/shell/-/issues/1">issue</a>)</li> </ul> <h2>libssc</h2> <ul> <li>Allow for <code>python3</code> as interpreter as well (<a href="https://codeberg.org/DylanVanAssche/libssc/pulls/61">MR</a>)</li> <li>Don't leak unprefixed symbols into ABI (<a href="https://codeberg.org/DylanVanAssche/libssc/pulls/63">MR</a>)</li> <li>Improve info on test failures (<a href="https://codeberg.org/DylanVanAssche/libssc/pulls/64">MR</a>)</li> <li>Support mutiarch when loading libqrtr (<a href="https://codeberg.org/DylanVanAssche/libssc/pulls/65">MR</a>)</li> </ul> <h2>ModemManager</h2> <ul> <li>Cell Broadcast: Allow to set channel list via API (<a href="https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1294">MR</a>)</li> </ul> <h2>Waycheck</h2> <ul> <li>Add Phosh's protocols (<a href="https://gitlab.freedesktop.org/serebit/waycheck/-/merge_requests/16">MR</a>)</li> </ul> <h2>Bug reports</h2> <ul> <li>Support haptic feedback on Linux in Firefox (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1945306">Bug</a>)</li> <li>Get pmOS to boot again on Nokia 2780 (<a href="https://gitlab.postmarketos.org/postmarketOS/pmaports/-/issues/3562">Bug</a>)</li> </ul> <h2>Reviews</h2> <p>This is not code by me but reviews on other peoples code. The list is a slightly incomplete. Thanks for the contributions!</p> <ul> <li>Debian: qcom-phone-utils rework (<a href="https://salsa.debian.org/DebianOnMobile-team/qcom-phone-utils/-/merge_requests/12">MR</a>)</li> <li>Simplify ui files (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1627">MR</a>) - partially merged</li> <li>calls: Implement ussd interface for ofono (<a href="https://gitlab.gnome.org/GNOME/calls/-/merge_requests/742">MR</a>)</li> <li>chatty: Build docs using gi-docgen (<a href="https://gitlab.gnome.org/World/Chatty/-/merge_requests/1426">MR</a>)</li> <li>chatty: Search related improvements (<a href="https://gitlab.gnome.org/World/Chatty/-/merge_requests/1451">MR</a>)</li> <li>chatty: Fix crash on stuck SMS removal (<a href="https://gitlab.gnome.org/World/Chatty/-/merge_requests/1460">MR</a>)</li> <li>feedbackd: stop flash when "prefer flash" is disabled (<a href="https://source.puri.sm/Librem5/feedbackd/-/merge_requests/153">MR</a>) - merged</li> <li>gmobile: Support for nothingphone notch (<a href="https://gitlab.gnome.org/World/Phosh/gmobile/-/merge_requests/59">MR</a>)</li> <li>iio-sensor-proxy: polkit for compass (<a href="https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/issues/405">MR</a>) - merged</li> <li>libcmatrix: Improved error code (<a href="https://source.puri.sm/Librem5/libcmatrix/-/merge_requests/108">MR</a>) - merged</li> <li>libcmatrix: Load room members is current (<a href="https://gitlab.gnome.org/GNOME/calls/-/merge_requests/742">MR</a>) - merged</li> <li>libcmatrix: Start 0.0.4 cycle (<a href="https://source.puri.sm/Librem5/libcmatrix/-/merge_requests/106">MR</a>) - merged</li> <li>libhosh-rs: Update to 0.45~rc1 (<a href="https://gitlab.gnome.org/guidog/libphosh-rs/-/merge_requests/32">MR</a>) - merged</li> <li>libphosh-rs: Update to reduced API surface (<a href="https://gitlab.gnome.org/guidog/libphosh-rs/-/merge_requests/30?commit_id=11674126ef7d6fe6f27da7731de7a88504a22f1f">MR</a>) - merged</li> <li>phoc: Use color-rect for shields: (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/647">MR</a>) - merged</li> <li>phoc: unresponsive toplevel state (<a href="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/196">MR</a>)</li> <li>phoc: view: Don't multiply by scale in <code>get_geometry_default</code> (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/655">MR</a>)</li> <li>phoc: render: Fix subsurface scaling when rendering to buffer (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/654">MR</a>)</li> <li>phoc: render: Avoid rendering textures with alpha set to zero (<a href="https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info/-/merge_requests/119">MR</a>)</li> <li>phoc: Render a spinner on output shield (<a href="https://gitlab.gnome.org/World/Phosh/phoc/-/merge_requests/646">MR</a>)</li> <li>phosh: Manage libpohsh API version separately (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1631">MR</a>) - merged</li> <li>phosh: Prepare container APIs for GTK4 (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1632">MR</a>)</li> <li>phosh: Reduce API surface further (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1637">MR</a>) - merged</li> <li>phosh: Simplify UI files for GTK4 migration (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1624">MR</a>) - merged</li> <li>phosh: Simplify gvc-channel bar (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1649">MR</a>) - merged</li> <li>phosh: Simplify parent lookup (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1646">MR</a>) - merged</li> <li>phosh: Split out private header for LF (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1637">MR</a>) - merged</li> <li>phosh: Use symbols file for libphosh (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1638">MR</a>) - merged</li> <li>phosh: stylesheet: Improve legibility of app grid and top bar (<a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1658">MR</a>)</li> <li>several mobile-broadband-provider-info updates under (<a href="https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info/-/merge_requests/">MR</a>) - mostly merged</li> </ul> <h3>Help Development</h3> <p>If you want to support my work see <a href="https://honk.sigxcpu.org/piki/donations/">donations</a>.</p> <h3>Comments?</h3> <p>Join the <a href="https://ruhr.social/@agx/114087442476287545">Fediverse thread</a></p> </div> <p class="date"> <a href="https://honk.sigxcpu.org/con/Free_Software_Activities_February_2025.html">01 March, 2025 01:38PM</a> </p> </div> </div> </div> <div class="channel"> <h2 class="planet-title"> <a href="https://abbbi.github.io//" title="Michael Ablassmeier">Michael Ablassmeier</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://abbbi.github.io//pbsav/_hide\" onClick=\"exclude( 'https://abbbi.github.io//pbsav/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://abbbi.github.io//pbsav/_show\" style=\"display:none;\" onClick=\"show( 'https://abbbi.github.io//pbsav/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://abbbi.github.io//pbsav/" class="https://abbbi.github.io//pbsav/"> <div class="entry"> <h3 class="entry-title"> <a href="https://abbbi.github.io//pbsav/">pbsav - scan backups on proxmox backup server via clamav</a> </h3> <div class="content"> <p>Little side project this weekend:</p> <p><a href="https://github.com/abbbi/pbsav">pbsav</a></p> <p>Small utility to scan virtual machine backups on PBS via clamav.</p> </div> <p class="date"> <a href="https://abbbi.github.io//pbsav/">01 March, 2025 12:00AM</a> </p> </div> </div> </div> <h1>February 28, 2025</h1> <div class="channel"> <h2 class="planet-title"> <a href="http://www.hungry.com/~pere/blog/" title="Petter Reinholdtsen - Entries tagged english">Petter Reinholdtsen</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html_hide\" onClick=\"exclude( 'http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html_show\" style=\"display:none;\" onClick=\"show( 'http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html" class="http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html"> <div class="entry"> <h3 class="entry-title"> <a href="http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html">Brushing up on old packages in Xiph and Debian</a> </h3> <div class="content"> <p>Since my motivation boost in the beginning of the month caused me to wrap up a new release of <tt><a href="https://xiph.org/oggz/">liboggz</a></tt>, I have used the same boost to wrap up new editions of <tt><a href="https://xiph.org/fishsound/">libfishsound</a></tt>, <tt><a href="https://gitlab.xiph.org/xiph/liboggplay/">liboggplay</a></tt> and <tt><a href="https://wiki.xiph.org/index.php/OggKate">libkate</a></tt> too. These have been tagged in upstream git, but not yet published on the Xiph download location. I am waiting for someone with access to have time to move the tarballs there, I hope it will happen in a few days. The same is the case for a minor update of liboggz too.</p> <p>As I was looking at Xiph packages lacking updates, it occurred to me that there are packages in Debian that have not received a new upload in a long time. Looking for a way to identify them, I came across the <tt>ltnu</tt> script from the <tt><a href="https://tracker.debian.org/pkg/devscripts">devscripts</a></tt> package. It can sort by last update, packages maintained by a single user/group, and is useful to figure out which packages a single maintainer should have a look at. But I wanted a archive wide summary. Based on the <a href="https://udd.debian.org/">UDD</a> SQL query used by ltnu, I ended up with the following command:</p> <pre>#!/bin/sh env PGPASSWORD=udd-mirror psql --host=udd-mirror.debian.net --user=udd-mirror udd --command=" select source, max(version) as ver, max(date) as uploaded from upload_history where distribution='unstable' and source in (select source from sources where release='sid') group by source order by max(date) asc limit 50;" </pre> <p>This will sort all source packages in Debian by upload date, and list the 50 oldest ones. The end result is a list of packages I suspect could use some attention:</p> <pre> source | ver | uploaded -----------------------------+-------------------------+------------------------ xserver-xorg-video-ivtvdev | 1.1.2-1 | 2011-02-09 22:26:27+00 dynamite | 0.1.1-2 | 2011-04-30 16:47:20+00 xkbind | 2010.05.20-1 | 2011-05-02 22:48:05+00 libspctag | 0.2-1 | 2011-09-22 18:47:07+00 gromit | 20041213-9 | 2011-11-13 21:02:56+00 s3switch | 0.1-1 | 2011-11-22 15:47:40+00 cd5 | 0.1-3 | 2011-12-07 21:19:05+00 xserver-xorg-video-glide | 1.2.0-1 | 2011-12-30 16:50:48+00 blahtexml | 0.9-1.1 | 2012-04-25 11:32:11+00 aggregate | 1.6-7 | 2012-05-01 00:47:11+00 rtfilter | 1.1-4 | 2012-05-11 12:50:00+00 sic | 1.1-5 | 2012-05-11 19:10:31+00 kbdd | 0.6-4 | 2012-05-12 07:33:32+00 logtop | 0.4.3-1 | 2012-06-05 23:04:20+00 gbemol | 0.3.2-2 | 2012-06-26 17:03:11+00 pidgin-mra | 20100304-1 | 2012-06-29 23:07:41+00 mumudvb | 1.7.1-1 | 2012-06-30 09:12:14+00 libdr-sundown-perl | 0.02-1 | 2012-08-18 10:00:07+00 ztex-bmp | 20120314-2 | 2012-08-18 19:47:55+00 display-dhammapada | 1.0-0.1 | 2012-12-19 12:02:32+00 eot-utils | 1.1-1 | 2013-02-19 17:02:28+00 multiwatch | 1.0.0-rc1+really1.0.0-1 | 2013-02-19 17:02:35+00 pidgin-latex | 1.5.0-1 | 2013-04-04 15:03:43+00 libkeepalive | 0.2-1 | 2013-04-08 22:00:07+00 dfu-programmer | 0.6.1-1 | 2013-04-23 13:32:32+00 libb64 | 1.2-3 | 2013-05-05 21:04:51+00 i810switch | 0.6.5-7.1 | 2013-05-10 13:03:18+00 premake4 | 4.3+repack1-2 | 2013-05-31 12:48:51+00 unagi | 0.3.4-1 | 2013-06-05 11:19:32+00 mod-vhost-ldap | 2.4.0-1 | 2013-07-12 07:19:00+00 libapache2-mod-ldap-userdir | 1.1.19-2.1 | 2013-07-12 21:22:48+00 w9wm | 0.4.2-8 | 2013-07-18 11:49:10+00 vish | 0.0.20130812-1 | 2013-08-12 21:10:37+00 xfishtank | 2.5-1 | 2013-08-20 17:34:06+00 wap-wml-tools | 0.0.4-7 | 2013-08-21 16:19:10+00 ttysnoop | 0.12d-6 | 2013-08-24 17:33:09+00 libkaz | 1.21-2 | 2013-09-02 16:00:10+00 rarpd | 0.981107-9 | 2013-09-02 19:48:24+00 libimager-qrcode-perl | 0.033-1.2 | 2013-09-04 21:06:31+00 dov4l | 0.9+repack-1 | 2013-09-22 19:33:25+00 textdraw | 0.2+ds-0+nmu1 | 2013-10-07 21:25:03+00 gzrt | 0.8-1 | 2013-10-08 06:33:13+00 away | 0.9.5+ds-0+nmu2 | 2013-10-25 01:18:18+00 jshon | 20131010-1 | 2013-11-30 00:00:11+00 libstar-parser-perl | 0.59-4 | 2013-12-23 21:50:43+00 gcal | 3.6.3-3 | 2013-12-29 18:33:29+00 fonts-larabie | 1:20011216-5 | 2014-01-02 21:20:49+00 ccd2iso | 0.3-4 | 2014-01-28 06:33:35+00 kerneltop | 0.91-1 | 2014-02-04 12:03:30+00 vera++ | 1.2.1-2 | 2014-02-04 21:21:37+00 (50 rows) </pre> <p>So there are 8 packages last uploaded to unstable in 2011, 12 packages in 2012 and 26 packages in 2013. I suspect their maintainers need help and we should all offer our assistance. I already contacted two of them and hope the rest of the Debian community will chip in to help too. We should ensure any Debian specific patches are passed upstream if they still exist, that the package is brought up to speed with the latest Debian policy, as well as ensure the source can built with the current compiler set in Debian.</p> <p>As usual, if you use Bitcoin and want to show your support of my activities, please send Bitcoin donations to my address <b><a>15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b</a></b>.</p> </div> <p class="date"> <a href="http://www.hungry.com/~pere/blog/Brushing_up_on_old_packages_in_Xiph_and_Debian.html">28 February, 2025 03:45PM</a> </p> </div> </div> </div> <h1></h1> <div class="channel"> <a href="https://jmtd.net/log/"> <img class="face" src="heads/jmtd.png" width="65" height="85" alt="hackergotchi for Jonathan Dowland" /> </a> <h2 class="planet-title"> <a href="https://jmtd.net/log/" title="Jonathan Dowland's Weblog">Jonathan Dowland</a> <script type="text/javascript"> <!-- document.write( "<a href=\"#\" id=\"https://jmtd.net/log/printables_feed/_hide\" onClick=\"exclude( 'https://jmtd.net/log/printables_feed/' ); hideHosts(); return false;\"><img src=\"common/minus-8.png\" style=\"border: none;\" title=\"Hide Author\" alt=\"Hide Author\" height=\"8\" width=\"8\"><\/a> <a href=\"#\" id=\"https://jmtd.net/log/printables_feed/_show\" style=\"display:none;\" onClick=\"show( 'https://jmtd.net/log/printables_feed/' ); return false;\"><img src=\"common/plus-8.png\" style=\"border: none;\" title=\"Show Author\" alt=\"Show Author\" height=\"8\" width=\"8\"><\/a>" ); --> </script> </h2> <div id="https://jmtd.net/log/printables_feed/" class="https://jmtd.net/log/printables_feed/"> <div class="entry"> <h3 class="entry-title"> <a href="https://jmtd.net/log/printables_feed/">printables.com feed</a> </h3> <div class="content"> <p>I wanted to follow new content posted to <a href="https://printables.com">Printables.com</a> with a feed reader, but Printables.com doesn't provide one. Neither do the other obvious 3d model catalogues. So, I started building one.</p> <p>I have something that spits out an Atom feed and a couple of beta testers gave me some valuable feedback. I had planned to make it public, with the ultimate goal being to convince Printables.com to implement feeds themselves.</p> <p>Meanwhile, I stumbled across someone else who has done basically the same thing. Here are 3<sup>rd</sup> party feeds for</p> <ul> <li>trending - <a href="https://dyn.tedder.me/rss/printables/trending.json">https://dyn.tedder.me/rss/printables/trending.json</a></li> <li>top rated - <a href="https://dyn.tedder.me/rss/printables/top_rated.json">https://dyn.tedder.me/rss/printables/top_rated.json</a></li> <li>top downloads - <a href="https://dyn.tedder.me/rss/printables/top_downloads.json">https://dyn.tedder.me/rss/printables/top_downloads.json</a></li> </ul> <p>The format of their feeds is <a href="https://jsonfeed.org/version/1.1">JSON-Feed</a>, which is new to me. <a href="https://freshrss.org/">FreshRSS</a> and <a href="https://netnewswire.com/">NetNewsWire</a> seems happy with it. (I went with Atom.) I may still release my take, if I find time to make one improvmment that my beta-testers suggested.</p> </div> <p class="date"> <a href="https://jmtd.net/log/printables_feed/">28 February, 2025 12:26PM</a> </p> </div> </div> </div> </div> <div id="sidebar"> <h1>Search</h1> <form method="GET" action="https://planet-search.debian.org/cgi-bin/search.cgi"> <input type="text" name="terms" value=""> </form> <hr /> <p> A complete feed is available in any of your favourite syndication formats linked by the buttons below. </p> <p> <a href="rss10.xml"><img class="button" src="common/rss10.png" width="80" height="15" alt="[RSS 1.0 Feed]"></a> <a href="rss20.xml"><img class="button" src="common/rss20.png" width="80" height="15" alt="[RSS 2.0 Feed]"></a> <a href="atom.xml"><img class="button" src="common/atom.png" width="80" height="15" alt="[Atom Feed]"></a> <a href="foafroll.xml"><img class="button" src="common/foaf.png" width="80" height="15" alt="[FOAF Subscriptions]"></a> <a href="opml.xml"><img class="button" src="common/opml.png" width="80" height="15" alt="[OPML Subscriptions]"></a> <a href="http://www.catb.org/hacker-emblem/"><img class="button" src="common/hacker.png" width="80" height="15" alt="[Hacker]"></a> <a href="https://www.intertwingly.net/code/venus/"><img class="button" src="common/planet.png" width="80" height="15" alt="[Planet]"></a> </p> <p> Last updated: 23 Mar 2025 14:45<br>All times are UTC.<br> Contact: <a href="mailto:planet@debian.org">Debian Planet Maintainers</a> </p> <h2>Planetarium</h2> <ul> <li><a href="https://planet.debian.org/">Planet Debian</a></li> <li><a href="https://planet.debian.org/deriv/">Planet Debian Derivatives</a></li> <li><a href="https://planet.debian.org/es/">Planet Debian Spanish</a></li> <li><a href="https://planet.debian.org/fr/">Planet Debian French</a></li> </ul> <div id="unhide-all" style="display:none;"> <h2>Hidden Feeds</h2> <p>You currently have hidden entries. <a href="#" onClick="excludeNone(); return false">Show all</a></p> </div> <h2>Subscriptions</h2> <ul> <li><a href="" title=""></a> <a href="">(feed)</a></li> <li><a href="https://abhijithpa.in/" title="Abhijith PA | അഭിജിത്ത് പി എ">Abhijith PA</a> <a href="https://abhijithpa.in/feed.debian.xml">(feed)</a></li> <li><a href="https://ajadi-abiola.github.io/" title="Abiola Ajadi">Abiola Ajadi</a> <a href="https://ajadi-abiola.github.io/feed.xml">(feed)</a></li> <li><a href="http://adam.rosi-kessel.org/weblog" title="The Substantially Similar Weblog">Adam Rosi-Kessel</a> <a href="http://adam.rosi-kessel.org/weblog/feed">(feed)</a></li> <li><a href="https://foolcontrol.org" title="FoolControl: Phear the penguin">Adnan Hodzic</a> <a href="https://foolcontrol.org/?feed=rss2">(feed)</a></li> <li><a href="https://deaddabe.fr/" title="deaddabe - debian">Agathe Porte</a> <a href="https://deaddabe.fr/feeds/tag.debian.atom.xml">(feed)</a></li> <li><a href="http://aigarius.com/categories/debian-planet/" title="Aigarius Blog (Posts about Debian-planet)">Aigars Mahinovs</a> <a href="https://aigarius.com/categories/debian-planet.atom">(feed)</a></li> <li><a href="https://blogs.igalia.com/berto" title="Debian – The world won't listen">Alberto García</a> <a href="https://blogs.igalia.com/berto/category/debian/feed/">(feed)</a></li> <li><a href="http://codergals.github.io/" title="Coder Gals">Albiona Hoti</a> <a href="https://codergals.github.io/feed.xml">(feed)</a></li> <li><a href="http://alerios-en.blogspot.com/" title="alerios (english version)">Alejandro Rios P.</a> <a href="http://alerios-en.blogspot.com/atom.xml">(feed)</a></li> <li><a href="https://log.alexm.org" title="debian – my $log;">Alex Muntada</a> <a href="https://log.alexm.org/category/debian/feed/">(feed)</a></li> <li><a href="https://blog.snow-crash.org/tags/debian/" title="debian on a place called home">Alexander Wirt</a> <a href="https://blog.snow-crash.org/tags/debian/index.xml">(feed)</a></li> <li><a href="https://alexandreviau.ca/blog/" title="Alexandre Viau's blog">Alexandre Viau</a> <a href="https://alexandreviau.ca/blog/index.xml">(feed)</a></li> <li><a href="https://blog.creekorful.org/" title="Aloïs Micard">Aloïs Micard</a> <a href="https://blog.creekorful.org/index.xml">(feed)</a></li> <li><a href="https://ekaia.org/" title="Ana Guerrero Lopez - planet-debian">Ana Beatriz Guerrero Lopez</a> <a href="https://ekaia.org/blog/feed/planet-debian.rss">(feed)</a></li> <li><a href="https://moonkin.github.io/" title="Moonkin’s blog">Anastasia Tsikoza</a> <a href="https://moonkin.github.io/feed.xml">(feed)</a></li> <li><a href="https://activelow.net/tags/pdo/" title="pdo on Active Low">Andreas Bombe</a> <a href="https://activelow.net/tags/pdo/index.xml">(feed)</a></li> <li><a href="http://www.bebt.de/blog/debian" title="nutmeg's blog">Andreas Metzler</a> <a href="https://www.bebt.de/blog/debian/rss.xml">(feed)</a></li> <li><a href="https://www.gusnan.se/blog" title="Debian – Gusnans blog">Andreas Rönnquist</a> <a href="http://www.gusnan.se/blog/category/Debian/feed/">(feed)</a></li> <li><a href="http://schuldei.blogspot.com/" title="schuldei.org">Andreas Schuldei</a> <a href="http://schuldei.blogspot.com/atom.xml">(feed)</a></li> <li><a href="http://andreeleidenfrost.blogspot.com/" title="Andree&#39;s Debian &amp; General Musings">Andree Leidenfrost</a> <a href="http://andreeleidenfrost.blogspot.com/atom.xml">(feed)</a></li> <li><a href="http://libcxx-gsoc.blogspot.com/" title="GSoC 2012 libc++ porting blog">Andrej Belym</a> <a href="http://libcxx-gsoc.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="https://blog.shadura.me/" title="Andrej’s notes">Andrej Shadura</a> <a href="https://blog.shadura.me/atom.xml">(feed)</a></li> <li><a href="http://flosslinuxblog.blogspot.com/" title="FLOSSLinux">Andrew Cater</a> <a href="http://flosslinuxblog.blogspot.com/atom.xml">(feed)</a></li> <li><a href="http://blog.andrew.net.au" title="Diary of a geek">Andrew Pollock</a> <a href="http://blog.andrew.net.au/planetdebian/index.rss">(feed)</a></li> <li><a href="https://blog.koipond.org.uk" title="Debian – Koipond">Andy Simpkins</a> <a href="https://blog.koipond.org.uk/archives/tag/debian/feed">(feed)</a></li> <li><a href="https://anisakuci.com/" title="Anisa Kuci">Anisa Kuci</a> <a href="https://anisakuci.com/feed.xml">(feed)</a></li> <li><a href="https://anarc.at/tag/debian-planet/" title="pages tagged debian-planet">Antoine Beaupré</a> <a href="https://anarc.at/tag/debian-planet/index.rss">(feed)</a></li> <li><a href="https://gladk.de/tags/debian/" title="debian on gladk.de">Anton Gladky</a> <a href="https://gladk.de/tags/debian/index.xml">(feed)</a></li> <li><a href="https://terceiro.xyz/" title="Antonio Terceiro">Antonio Terceiro</a> <a href="https://terceiro.xyz/feed.xml">(feed)</a></li> <li><a href="https://antti-juhani.kaijanaho.fi/newblog" title="Debian – Antti-Juhani Kaijanaho">Antti-Juhani Kaijanaho</a> <a href="https://antti-juhani.kaijanaho.fi/newblog/archives/tag/debian/feed">(feed)</a></li> <li><a href="https://weeraman.com/" title="Anuradha Weeraman">Anuradha Weeraman</a> <a href="https://weeraman.com/rss/">(feed)</a></li> <li><a href="https://arianit2.wordpress.com" title="debian – Arianit's Blog">Arianit Dobroshi</a> <a href="https://arianit2.wordpress.com/tag/debian/feed/">(feed)</a></li> <li><a href="https://arnaudr.io/" title="Arnaud R - planet-debian">Arnaud Rebillout</a> <a href="https://arnaudr.io/feeds/tags/planet-debian.atom.xml">(feed)</a></li> <li><a href="https://blogs.gnome.org/happyaron" title="Debian – True EDGE">Aron Xu</a> <a href="https://blogs.gnome.org/happyaron/category/debian/feed/rss/">(feed)</a></li> <li><a href="http://www.arthurbdiniz.com/" title="Arthur Diniz">Arthur Diniz</a> <a href="https://arthurbdiniz.com/feed.xml">(feed)</a></li> <li><a href="https://ral-arturo.org/" title="ral-arturo.org">Arturo Borrero González</a> <a href="https://ral-arturo.org/feed.xml">(feed)</a></li> <li><a href="https://athoscr.me/categories/debian/" title="Debian on /home/athos">Athos Ribeiro</a> <a href="https://athoscr.me/categories/debian/index.xml">(feed)</a></li> <li><a href="https://blog.aurel32.net/" title="Aurélien Jarno">Aurelien Jarno</a> <a href="https://blog.aurel32.net/feed">(feed)</a></li> <li><a href="http://noone.org/blog/English/Computer/Shell" title="Blogging is futile">Axel Beckert</a> <a href="http://noone.org/blog/English/index.rss">(feed)</a></li> <li><a href="https://ayoyimika.hashnode.dev" title="Ayoyimika">Ayoyimika Ajibade</a> <a href="https://ayoyimika.hashnode.dev/rss.xml">(feed)</a></li> <li><a href="https://balasankarc.in/" title="Balasankar C">Balasankar 'Balu' C</a> <a href="https://balasankarc.in/tech/feed.xml">(feed)</a></li> <li><a href="https://bblank.thinkmo.de/" title="Some Place for Me">Bastian Blank</a> <a href="https://bblank.thinkmo.de/feeds/sub-debian-planet.atom.xml">(feed)</a></li> <li><a href="https://venthur.de/" title="still don't have a title">Bastian Venthur</a> <a href="https://venthur.de/atom.xml">(feed)</a></li> <li><a href="http://www.gag.com/bdale/blog/index.html" title="Bits from the Basement">Bdale Garbee</a> <a href="https://gag.com/bdale/blog/index.rss">(feed)</a></li> <li><a href="https://www.decadent.org.uk/ben/blog/" title="Better living through software">Ben Hutchings</a> <a href="https://www.decadent.org.uk/ben/blog/index.atom">(feed)</a></li> <li><a href="https://overbenny.wordpress.com" title="Planet Debian – Overbenny's Blog">Benjamin Drung</a> <a href="https://overbenny.wordpress.com/category/planet-debian/feed/atom/">(feed)</a></li> <li><a href="" title="">Benjamin Kerensa</a> <a href="https://benjaminkerensa.com/category/debian/feed">(feed)</a></li> <li><a href="https://mako.cc/copyrighteous" title="copyrighteous">Benjamin Mako Hill</a> <a href="https://mako.cc/copyrighteous/feed">(feed)</a></li> <li><a href="https://bzed.de/categories/linux/" title="linux on linux & the mountains">Bernd Zeimetz</a> <a href="https://bzed.de/categories/linux/index.xml">(feed)</a></li> <li><a href="http://blog.brlink.eu/index.html" title="Bernhard R. Link">Bernhard R. Link</a> <a href="http://blog.brlink.eu/changelog.rss">(feed)</a></li> <li><a href="https://gabriellacoleman.org/blog" title="Interprete">Biella Coleman</a> <a href="https://gabriellacoleman.org/blog/?feed=rss2">(feed)</a></li> <li><a href="https://dev.to/warbilly" title="DEV Community: Billy Warren">Billy Warren</a> <a href="https://dev.to/feed/warbilly">(feed)</a></li> <li><a href="https://bisco.org/tags/debian/" title="debian on bisco.org">Birger Schacht</a> <a href="https://bisco.org/tags/debian/index.xml">(feed)</a></li> <li><a href="https://bits.debian.org/" title="Bits from Debian">Bits from Debian</a> <a href="https://bits.debian.org/feeds/feed.rss">(feed)</a></li> <li><a href="https://www.sommitrealweird.co.uk/blog/" title="The World of SommitRealWeird.">Brett Parker</a> <a href="https://www.sommitrealweird.co.uk/feeds/blog/">(feed)</a></li> <li><a href="https://bgoglin.livejournal.com/" title="Brice Goglin's Blog">Brice Goglin</a> <a href="https://bgoglin.livejournal.com/data/rss?tag=planet.d.o">(feed)</a></li> <li><a href="https://balintreczey.hu/blog" title="debian – Obsessed with reality">Bálint Réczey</a> <a href="https://balintreczey.hu/blog/tag/debian/feed/">(feed)</a></li> <li><a href="https://wp.c9h.org/cj" title="debian – Clerical Rigor">C.J. Collier</a> <a href="https://wp.colliertech.org/cj/?cat=17&feed=rss2">(feed)</a></li> <li><a href="https://chainofcommand.hashnode.dev" title="Angles and Braces">Caleb Adepitan</a> <a href="https://chainofcommand.hashnode.dev/rss.xml">(feed)</a></li> <li><a href="https://stringpiggy.hpd.io" title="debian – StringPiggy">Candy Tsai</a> <a href="https://stringpiggy.hpd.io/tag/debian/feed/">(feed)</a></li> <li><a href="https://admincarlchenet.wordpress.com" title="Carl Chenet">Carl Chenet</a> <a href="https://admincarlchenet.wordpress.com/category/debian/feed/">(feed)</a></li> <li><a href="http://bootdebian.blogspot.com/" title="Improve the Debian boot process - blog">Carlos Villegas</a> <a href="http://bootdebian.blogspot.com/atom.xml">(feed)</a></li> <li><a href="https://www.charlz.net/" title="Charlz' Realm">Charles</a> <a href="https://www.charlz.net/feed.xml">(feed)</a></li> <li><a href="http://charles.plessy.org/Debian/planet/" title="Planet">Charles Plessy</a> <a href="https://charles.plessy.org/Debian/planet/index.en.rss">(feed)</a></li> <li><a href="https://crispygoth.livejournal.com/" title="ChrisB">Chris Butler</a> <a href="https://crispygoth.livejournal.com/data/rss?tag=planet">(feed)</a></li> <li><a href="https://chris-lamb.co.uk/blog/category/planet-debian" title="lamby: Items or syndication on Planet Debian.">Chris Lamb</a> <a href="https://chris-lamb.co.uk/blog/category/planet-debian/feed">(feed)</a></li> <li><a href="https://blog.lordsutch.com/" title="Signifying Nothing">Chris Lawrence</a> <a href="https://blog.lordsutch.com/feed/?topic=5&topic=12&topic=10&topic=49&author=1">(feed)</a></li> <li><a href="https://www.kvr.at/" title="Christian Kastner">Christian Kastner</a> <a href="https://www.kvr.at/rss.xml">(feed)</a></li> <li><a href="http://blog.spang.cc/tags/planet-debian/" title="tags/planet-debian">Christine Spang</a> <a href="http://blog.spang.cc/tags/planet-debian/index.rss">(feed)</a></li> <li><a href="https://www.df7cb.de/blog/tag/debian.html" title="Myon's Debian Blog">Christoph Berg</a> <a href="https://www.df7cb.de/blog/tag/debian.rss">(feed)</a></li> <li><a href="https://weblog.christoph-egger.org/" title="Christoph's last Weblog entries">Christoph Egger</a> <a href="https://weblog.christoph-egger.org//index.rss">(feed)</a></li> <li><a href="https://xana.scru.org" title="Yammering">Clint Adams</a> <a href="https://xana.scru.org/rivercrabbed-debian.atom">(feed)</a></li> <li><a href="https://www.chiark.greenend.org.uk/~cjwatson/blog/" title="Colin Watson's blog - planet-debian">Colin Watson</a> <a href="https://www.chiark.greenend.org.uk/~cjwatson/blog/feeds/tag/planet-debian.atom.xml">(feed)</a></li> <li><a href="http://blog.taz.net.au" title="Errata">Craig Sanders</a> <a href="http://blog.taz.net.au/feed/">(feed)</a></li> <li><a href="http://mraw.org/blog/" title="KiBi’s blog">Cyril Brulebois</a> <a href="https://mraw.org/blog/index.rss">(feed)</a></li> <li><a href="https://mirrorlynx.livejournal.com/" title="Dan Weber">Dan Weber</a> <a href="https://mirrorlynx.livejournal.com/data/rss">(feed)</a></li> <li><a href="https://dkg.fifthhorseman.net/blog/" title="dkg's blog">Daniel Kahn Gillmor</a> <a href="https://dkg.fifthhorseman.net/blog/feeds/all.atom.xml">(feed)</a></li> <li><a href="https://daniel-lange.com/" title="Daniel Lange's blog">Daniel Lange</a> <a href="https://daniel-lange.com/feeds/atom.xml">(feed)</a></li> <li><a href="https://www.wgdd.de/search/label/planet-debian" title="[erfahrungen, meinungen, halluzinationen]">Daniel Leidert</a> <a href="https://www.wgdd.de/feeds/posts/default/-/planet-debian">(feed)</a></li> <li><a href="http://tdi.github.io/" title="Blog">Dariusz Dwornikowski</a> <a href="https://tdi.github.io/feeds/all.atom.xml">(feed)</a></li> <li><a href="https://www.foxk.it/blog/" title="Blogs on Foxk.it">Dave Hibberd</a> <a href="https://foxk.it/blog/index.xml">(feed)</a></li> <li><a href="https://www.cs.unb.ca/~bremner//blog/tags/planet/" title="blog/tags/planet">David Bremner</a> <a href="http://www.cs.unb.ca/~bremner/blog/tags/planet/index.rss">(feed)</a></li> <li><a href="https://david.kalnischkies.de/blog" title="apt-get a life">David Kalnischkies</a> <a href="https://david.kalnischkies.de/blog/index.rss">(feed)</a></li> <li><a href="https://damog.net/blog/tag/debian/" title="debian on David Moreno's blog">David Moreno</a> <a href="https://damog.net/blog/tag/debian/atom.xml">(feed)</a></li> <li><a href="https://gravityboy.livejournal.com/" title="To The Point Of Collapse">David Nusinow</a> <a href="https://gravityboy.livejournal.com/data/rss">(feed)</a></li> <li><a href="http://www.hanskalabs.net/" title="HanskaLabs (planet)">David Paleino</a> <a href="http://www.hanskalabs.net/categories/planet.xml">(feed)</a></li> <li><a href="http://planetwatson.co.uk/categories/planet-debian/" title="Entries for the category Planet Debian">David Watson</a> <a href="http://planetwatson.co.uk/feeds/categories/planet-debian">(feed)</a></li> <li><a href="http://dwgsoc09blog.blogspot.com/search/label/to-debian-gsoc" title="David Wendt's GSoC Updates Blog">David Wendt Jr.</a> <a href="http://dwgsoc09blog.blogspot.com/feeds/posts/default/-/to-debian-gsoc">(feed)</a></li> <li><a href="http://zinosat.blogspot.com/" title="Yeah!">Davide Viti</a> <a href="http://zinosat.blogspot.com/atom.xml">(feed)</a></li> <li><a href="" title="">DebConf team</a> <a href="https://bits.debian.org/tag/debconf.html">(feed)</a></li> <li><a href="https://debianbrasil.org.br/" title="Debian Brasil">Debian Brasil</a> <a href="https://debianbrasil.org.br/english-feed.xml">(feed)</a></li> <li><a href="https://java-team.pages.debian.net/gsoc-kotlin-blog/" title="Debian GSoC Kotlin project">Debian GSoC Kotlin project blog</a> <a href="https://java-team.pages.debian.net/gsoc-kotlin-blog/atom.xml">(feed)</a></li> <li><a href="http://java.debian.net/blog/" title="Debian Java News">Debian Java Packaging Team</a> <a href="https://java.debian.net/blog/atom.xml">(feed)</a></li> <li><a href="http://debianmed.blogspot.com/" title="Debian in Biology and Medicine">Debian Med</a> <a href="http://feeds.feedburner.com/DebianInBiologyAndMedicine">(feed)</a></li> <li><a href="https://bits.debian.org/dpl/" title="Debian Project Leader Blog">Debian Project Leader</a> <a href="https://bits.debian.org/dpl/feeds/feed.rss">(feed)</a></li> <li><a href="https://wordpress.debian.social" title="debian.social blog">Debian Social Team</a> <a href="https://wordpress.debian.social/feed/">(feed)</a></li> <li><a href="https://dsa.debian.org//dsablog/" title="Debian System Administrators' Blog">Debian Sysadmin Team</a> <a href="https://dsa.debian.org/dsablog/index.rss">(feed)</a></li> <li><a href="https://xmpp-team.pages.debian.net/blog/" title="Bits from the Debian XMPP Team">Debian XMPP Team</a> <a href="https://xmpp-team.pages.debian.net/blog/feeds/atom.xml">(feed)</a></li> <li><a href="https://debichem-team.pages.debian.net/" title="The debichem group">Debichem Team</a> <a href="https://debichem-team.pages.debian.net/feed.xml">(feed)</a></li> <li><a href="https://medium.com/@gajbhiyedeepanshu?source=rss-ff6d7d57bab6------2" title="Stories by Deepanshu on Medium">Deepanshu Gajbhiye</a> <a href="https://medium.com/feed/@gajbhiyedeepanshu">(feed)</a></li> <li><a href="https://blog.odyx.org" title="english – /var/log/OdyX">Didier Raboud</a> <a href="https://blog.odyx.org/tag/en/feed/">(feed)</a></li> <li><a href="http://notes.secretsauce.net" title="Dima Kogan">Dima Kogan</a> <a href="https://notes.secretsauce.net/index.xml">(feed)</a></li> <li><a href="http://blog.surgut.co.uk/search/label/debian-planet" title="Surgut">Dimitri John Ledkov</a> <a href="http://blog.surgut.co.uk/feeds/posts/default/-/debian-planet">(feed)</a></li> <li><a href="http://dirk.eddelbuettel.com/blog" title="Thinking inside the box">Dirk Eddelbuettel</a> <a href="https://dirk.eddelbuettel.com/blog/index.rss">(feed)</a></li> <li><a href="https://dev.to/0xfaker" title="DEV Community: Divine Attah-Ohiemi">Divine Attah-Ohiemi</a> <a href="https://dev.to/feed/0xfaker">(feed)</a></li> <li><a href="https://mitya57.me/weblog/" title="mitya57’s weblog - Planet">Dmitry Shachnev</a> <a href="https://mitya57.me/weblog/feeds/planet.atom.xml">(feed)</a></li> <li><a href="https://web.itu.edu.tr/celikd" title="helloworlditsme">Dogukan Celik</a> <a href="https://web.itu.edu.tr/celikd/feed/">(feed)</a></li> <li><a href="https://ddumont.wordpress.com" title="Dominique Dumont's Blog">Dominique Dumont</a> <a href="https://ddumont.wordpress.com/feed/">(feed)</a></li> <li><a href="https://www.donarmstrong.com/tags/debian/" title="pages tagged debian">Don Armstrong</a> <a href="https://www.donarmstrong.com/tags/debian/index.rss">(feed)</a></li> <li><a href="http://ramblingfoo.blogspot.com/" title="Rambling around foo">Eddy Petrișor</a> <a href="http://feeds.feedburner.com/RamblingFoo">(feed)</a></li> <li><a href="https://dhole.github.io/categories/debian/" title="debian on Dhole's blog">Eduard Sanou</a> <a href="https://dhole.github.io/categories/debian/index.xml">(feed)</a></li> <li><a href="https://eduardo.macan.eng.br" title="Eduardo Maçan">Eduardo Marcel Macan</a> <a href="https://eduardo.macan.eng.br/category/debian-en/feed/">(feed)</a></li> <li><a href="https://edwardbetts.com/" title="Edward Betts">Edward Betts</a> <a href="https://edwardbetts.com/feed_rss_created.xml">(feed)</a></li> <li><a href="https://hashman.ca/" title="hashman.ca">Elana Hashman</a> <a href="https://hashman.ca/feeds/all.atom.xml">(feed)</a></li> <li><a href="https://www.linux.it/~ema/" title="Emanuele Rocca">Emanuele Rocca</a> <a href="https://www.linux.it/~ema/index.xml">(feed)</a></li> <li><a href="http://emilio.pozuelo.org" title="Planet Debian – Emilio Pozuelo Monfort's blog">Emilio Pozuelo Monfort</a> <a href="https://emilio.pozuelo.org/?cat=13&feed=atom">(feed)</a></li> <li><a href="https://00formicapunk00.wordpress.com" title="floss – formicapunk">Emmanuel Kasper</a> <a href="https://00formicapunk00.wordpress.com/tag/floss/feed/">(feed)</a></li> <li><a href="http://www.enricozini.org/tags/pdo" title="Enrico Zini: posts with tag pdo">Enrico Zini</a> <a href="https://www.enricozini.org/tags/pdo/index.rss">(feed)</a></li> <li><a href="https://eriberto.pro.br/blog" title="Planet en – Eriberto Blog">Eriberto Mota</a> <a href="http://eriberto.pro.br/blog/tag/planet-en/feed/">(feed)</a></li> <li><a href="https://ze-dinosaur.livejournal.com/" title="apparently I'm a dinosaur">Eric Dorland</a> <a href="https://ze-dinosaur.livejournal.com/data/rss">(feed)</a></li> <li><a href="https://www.vitavonni.de/blog/" title="Techblogging">Erich Schubert</a> <a href="https://www.vitavonni.de/blog/feeds/en.atom">(feed)</a></li> <li><a href="https://www.ieugen.ro/" title="(defn Eugen-Stan [_] awesome)">Eugen Stan</a> <a href="https://www.ieugen.ro/feed.xml">(feed)</a></li> <li><a href="https://jackyf.livejournal.com/" title="JackYF's blog">Eugene V. Lyubimkin</a> <a href="https://jackyf.livejournal.com/data/rss?tag=debian-en">(feed)</a></li> <li><a href="https://www.die-welt.net/" title="die-welt.net">Evgeni Golov</a> <a href="https://www.die-welt.net/rss.xml">(feed)</a></li> <li><a href="http://web2unu.ro" title="Web2Unu Blog » Debian">Floris Stoica-Marcu</a> <a href="http://web2unu.ro/?feed=rss2&cat=2">(feed)</a></li> <li><a href="https://fottsia.wordpress.com" title="My outreachy project blog">Foteini Tsiami</a> <a href="https://fottsia.wordpress.com/feed/">(feed)</a></li> <li><a href="https://feeding.cloud.geek.nz/tags/debian/" title="pages tagged debian">François Marier</a> <a href="https://feeding.cloud.geek.nz/tags/debian/index.rss">(feed)</a></li> <li><a href="https://www.freexian.com/tags/planet-debian/" title="planet-debian on Freexian">Freexian Collaborators</a> <a href="https://www.freexian.com/tags/planet-debian/index.xml">(feed)</a></li> <li><a href="https://asylum.madhouse-project.org/blog/tags/.planet.debian/" title="Asylum Archives: .planet.debian">Gergely Nagy</a> <a href="https://asylum.madhouse-project.org/blog/tags/.planet.debian/atom.xml">(feed)</a></li> <li><a href="http://cateee.blogspot.com/" title="Cateee">Giacomo Catenazzi</a> <a href="http://cateee.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="https://www.giovannimascellani.eu/" title="Gio's Tilde - debian-planet">Giovanni Mascellani</a> <a href="https://www.giovannimascellani.eu/feeds/debian-planet.atom.xml">(feed)</a></li> <li><a href="https://www.iuculano.it/category/linux/debian/debian-planet-debian/" title="Debian Planet Archivi - Giuseppe">Giuseppe Iuculano</a> <a href="https://www.iuculano.it/category/debian-planet-debian/feed/">(feed)</a></li> <li><a href="https://info.comodo.priv.at/blog/" title="gregoa's blog - entries tagged planetdebian">Gregor Herrmann</a> <a href="https://info.comodo.priv.at/blog/tags/planetdebian/planetdebian.rss">(feed)</a></li> <li><a href="https://gcolpart.evolix.net/blog21" title="Debian – Gregory Colpart's blog">Gregory Colpart</a> <a href="https://gcolpart.evolix.net/blog21/category/debian/feed/">(feed)</a></li> <li><a href="https://honk.sigxcpu.org/con/" title="Colors of Noise - Entries tagged planetdebian">Guido Günther</a> <a href="https://honk.sigxcpu.org/con/tags/planetdebian/planetdebian.rss">(feed)</a></li> <li><a href="https://phosh.mobi/tags/planetdebian/" title="Planetdebian on Phosh">Guido Günther</a> <a href="https://phosh.mobi/tags/planetdebian/index.xml">(feed)</a></li> <li><a href="https://puida.xyz/tags/debian/index.xml" title="Debian on puida.xyz">Guilherme Puida Moreira</a> <a href="https://puida.xyz/tags/debian/index.xml">(feed)</a></li> <li><a href="https://gwolf.org" title="Gunnar Wolf - Nice grey life">Gunnar Wolf</a> <a href="https://gwolf.org/rss.xml">(feed)</a></li> <li><a href="http://stratusandtheswirl.blogspot.com/" title="stratus and the swirl">Gustavo Franco</a> <a href="http://feeds.feedburner.com/StratusAndTheSwirl">(feed)</a></li> <li><a href="http://grmontesino.blogspot.com/search/label/Debian" title="Gustavo's Blog">Gustavo R. Montesino</a> <a href="http://grmontesino.blogspot.com/feeds/posts/default/-/Debian/">(feed)</a></li> <li><a href="https://henrich-on-debian.blogspot.com/" title="Henrich plays with Debian">Hideki Yamane</a> <a href="https://henrich-on-debian.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="http://nibbles.halon.org.uk" title="Quick Nibbles » Debian">Héctor Orón Martínez</a> <a href="http://nibbles.halon.org.uk/category/tech/debian/feed/atom/">(feed)</a></li> <li><a href="https://irl.xyz/tags/planet-debian/" title="Planet Debian on IRL.XYZ">Iain R. Learmonth</a> <a href="https://irl.xyz/tags/planet-debian/index.xml">(feed)</a></li> <li><a href="https://diziet.dreamwidth.org/" title="Ian Jackson">Ian Jackson</a> <a href="https://diziet.dreamwidth.org/data/atom">(feed)</a></li> <li><a href="https://www.technovelty.org/" title="technovelty">Ian Wienand</a> <a href="https://www.technovelty.org/index.atom.xml">(feed)</a></li> <li><a href="http://genibel.org/blog/index.php/" title="Igor's blog">Igor Genibel</a> <a href="https://www.hotbot.fr">(feed)</a></li> <li><a href="https://blog.windfluechter.net" title="Debian – WindfluechterNet Blog">Ingo Juergensmann</a> <a href="https://blog.windfluechter.net/category/debian/feed/">(feed)</a></li> <li><a href="https://k1024.org" title="iustin - all posts">Iustin Pop</a> <a href="https://k1024.org/index.atom">(feed)</a></li> <li><a href="https://tookmund.com/" title="">Jacob Adams</a> <a href="https://tookmund.com/feed.xml">(feed)</a></li> <li><a href="https://blog.james.rcpt.to" title="Linux – JEB's Blog">James Bromberger</a> <a href="https://blog.james.rcpt.to/category/computing/linux/feed/">(feed)</a></li> <li><a href="https://jamessan.com/~jamessan//tags/planet-debian/" title="pages tagged planet-debian">James McCoy</a> <a href="https://jamessan.com/~jamessan/tags/planet-debian/index.rss">(feed)</a></li> <li><a href="https://www.sorced.com/" title="Sasquach wears a yellow hat">James Morrison</a> <a href="https://www.sorced.com/feeds/posts/default?alt=atom">(feed)</a></li> <li><a href="https://jvalleroy.fbx.one/wordpress" title="James Valleroy">James Valleroy</a> <a href="https://jvalleroy.fbx.one/wordpress/?feed=rss2">(feed)</a></li> <li><a href="https://current.workingdirectory.net/tags/debian/" title="debian on Website of Jamie McClelland">Jamie McClelland</a> <a href="https://current.workingdirectory.net/tags/debian/index.xml">(feed)</a></li> <li><a href="https://jaminyprabaharan.wordpress.com" title="">Jaminy Prabaharan</a> <a href="https://jaminyprabaharan.wordpress.com/feed/">(feed)</a></li> <li><a href="https://debianstuff.dittberner.info/" title="Debian Stuff @ dittberner.info">Jan Dittberner</a> <a href="https://debianstuff.dittberner.info/rss.xml">(feed)</a></li> <li><a href="https://log.cyconet.org/" title="Planet - Cyconet Blog">Jan Wagner</a> <a href="https://log.cyconet.org/tag/planet/rss/">(feed)</a></li> <li><a href="https://jbailey.livejournal.com/" title="Bright lights shining upwards obscures the stars...">Jeff Bailey</a> <a href="https://jbailey.livejournal.com/data/rss">(feed)</a></li> <li><a href="https://www.licquia.org" title="The Licquia Blog">Jeff Licquia</a> <a href="http://www.licquia.org/feed/">(feed)</a></li> <li><a href="https://jeremy.bicha.net" title="Debian – Just Jeremy">Jeremy Bicha</a> <a href="https://jeremy.bicha.net/category/debian/feed/?mrss=off">(feed)</a></li> <li><a href="https://sophiejjj.wordpress.com" title="My journey of FOSS">Jingjie Jiang</a> <a href="https://sophiejjj.wordpress.com/feed/">(feed)</a></li> <li><a href="https://apebox.org/wordpress" title="debian – APEBOX.ORG">Jo Shields</a> <a href="https://apebox.org/wordpress/tag/debian/feed">(feed)</a></li> <li><a href="https://www.joachim-breitner.de/blog" title="nomeata’s mind shares">Joachim Breitner</a> <a href="https://www.joachim-breitner.de/blog/tag/English_feed.rss">(feed)</a></li> <li><a href="https://blog.ganneff.de/" title="Ganneff's Little Blog">Joerg Jaspert</a> <a href="https://blog.ganneff.de/atom.xml">(feed)</a></li> <li><a href="http://joeyh.name/blog/" title="see shy jo">Joey Hess</a> <a href="https://joeyh.name/blog/index.rss">(feed)</a></li> <li><a href="https://blog.mister-muffin.de/feed/None" title="Mister Muffin Blog">Johannes Schauer</a> <a href="https://blog.mister-muffin.de/feed/index.xml">(feed)</a></li> <li><a href="https://changelog.complete.org" title="The Changelog">John Goerzen</a> <a href="https://changelog.complete.org/feed">(feed)</a></li> <li><a href="https://blog.freesources.org//" title="mejo roaming">Jonas Meurer</a> <a href="https://blog.freesources.org/index.atom">(feed)</a></li> <li><a href="http://dr.jones.dk//blog/" title="blog">Jonas Smedegaard</a> <a href="https://dr.jones.dk/blog/index.en.atom">(feed)</a></li> <li><a href="https://jonathancarter.org" title="Jonathan Carter">Jonathan Carter</a> <a href="https://jonathancarter.org/feed/">(feed)</a></li> <li><a href="https://jmtd.net/log/" title="Jonathan Dowland's Weblog">Jonathan Dowland</a> <a href="https://jmtd.net/log/feed/">(feed)</a></li> <li><a href="https://www.earth.li/~noodles/blog/" title="Noodles' Emptiness">Jonathan McDowell</a> <a href="https://www.earth.li/~noodles/blog/feed.xml">(feed)</a></li> <li><a href="https://www.jwiltshire.org.uk" title="planet-debian – jwiltshire.org.uk">Jonathan Wiltshire</a> <a href="https://www.jwiltshire.org.uk/tag/planet-debian/feed/">(feed)</a></li> <li><a href="https://jawnsy.wordpress.com" title="Debian – Jawnsy’s Journal on Life, Software and Engineering">Jonathan Yu</a> <a href="https://jawnsy.wordpress.com/tag/debian/feed/">(feed)</a></li> <li><a href="https://jonnylamb.com" title="Planet Debian">Jonny Lamb</a> <a href="https://jonnylamb.com/category/planet-debian/feed/">(feed)</a></li> <li><a href="https://oskuro.net/blog" title="I still don't have a title">Jordi Mallach</a> <a href="https://oskuro.net/blog/?flav=rss">(feed)</a></li> <li><a href="http://josephbisch.com/tags/debian/" title="debian on Joseph Bisch">Joseph Bisch</a> <a href="http://josephbisch.com/tags/debian/index.xml">(feed)</a></li> <li><a href="https://np237.livejournal.com/" title="Joss's blog">Josselin Mouette</a> <a href="https://np237.livejournal.com/data/rss">(feed)</a></li> <li><a href="https://gnucrash.wordpress.com" title="DebianPl – Alicatismo ilustrado.">Juan Luis Belmonte</a> <a href="https://gnucrash.wordpress.com/category/debianpl/feed/">(feed)</a></li> <li><a href="https://blog.jak-linux.org/post/" title="Posts on Blog of Julian Andres Klode">Julian Andres Klode</a> <a href="https://blog.jak-linux.org/post/index.xml">(feed)</a></li> <li><a href="http://silicone.homelinux.org" title="debian-planet – Silicone's web">Julien Viard de Galbert</a> <a href="http://silicone.homelinux.org/tag/debian-planet/feed/">(feed)</a></li> <li><a href="http://www.netfort.gr.jp/~dancer/diary/202503.html.en" title="Dancer's daily hackings">Junichi Uekawa</a> <a href="https://www.netfort.gr.jp/~dancer/diary/recententry-en.rdf">(feed)</a></li> <li><a href="http://blog.wooyd.org/" title="wiki">Jurij Smakov</a> <a href="http://blog.wooyd.org/index.rss">(feed)</a></li> <li><a href="https://teythoon.cryptobitch.de/" title="unprivileged user">Justus Winter</a> <a href="https://teythoon.cryptobitch.de/rss.xml">(feed)</a></li> <li><a href="https://www.carbon-project.org/" title="Cùran's life - Entries tagged debian">Kai Wasserbäch</a> <a href="https://www.carbon-project.org/tags/debian/debian.rss">(feed)</a></li> <li><a href="https://kalken.in/blog/" title="Blogs on Kalyani Kenekar">Kalyani Kenekar</a> <a href="https://kalken.in/blog/index.xml">(feed)</a></li> <li><a href="https://0x1f1f.wordpress.com" title="Localized Gujarati Geek">Kartik Mistry</a> <a href="https://0x1f1f.wordpress.com/feed/atom/">(feed)</a></li> <li><a href="https://kathara.in/blogs/" title="Blogs on Kathara Sasikumar">Kathara Sasikumar</a> <a href="https://kathara.in/blogs/index.xml">(feed)</a></li> <li><a href="https://outflux.net/blog" title="Debian – codeblog">Kees Cook</a> <a href="https://outflux.net/blog/archives/category/debian/feed/">(feed)</a></li> <li><a href="http://keithp.com/blog/" title="blog">Keith Packard</a> <a href="https://keithp.com/blog/index.rss">(feed)</a></li> <li><a href="https://kenhys.hatenablog.jp/archive/category/PlanetDebian" title="PlanetDebian - ひとりしずかに。">Kentaro Hayashi</a> <a href="https://kenhys.hatenablog.jp/rss/category/PlanetDebian">(feed)</a></li> <li><a href="https://blog.legoktm.com/" title="The Lego Mirror - debian">Kunal Mehta</a> <a href="https://blog.legoktm.com/feeds/tag-debian.atom.xml">(feed)</a></li> <li><a href="https://kwk.systems/blog/" title="Biosystems Engineering Blog (Posts about debian)">Kurt Kremitzki</a> <a href="https://www.kwk.systems/blog/categories/debian.xml">(feed)</a></li> <li><a href="https://www.roeckx.be/journal/" title="Kurt Roeckx's journal">Kurt Roeckx</a> <a href="https://www.roeckx.be/journal/index.rss">(feed)</a></li> <li><a href="https://larjona.wordpress.com" title="English – The bright side">Laura Arjona Reina</a> <a href="https://larjona.wordpress.com/tag/english/feed/">(feed)</a></li> <li><a href="http://allentiak.github.io/" title="Just a Blog">Leandro Doctors</a> <a href="https://allentiak.github.io/feed.xml">(feed)</a></li> <li><a href="https://leogg.wordpress.com" title="planet-debian – [comuNIdad]">Leandro Gómez</a> <a href="https://leogg.wordpress.com/category/planet-debian/feed/atom/">(feed)</a></li> <li><a href="https://costela.net" title="debian planet – costela.net">Leo 'costela' Antunes</a> <a href="https://costela.net/tag/debian-planet/feed/">(feed)</a></li> <li><a href="https://liorkaplan.wordpress.com" title="Free Software Universe">Lior Kaplan</a> <a href="https://liorkaplan.wordpress.com/feed/">(feed)</a></li> <li><a href="https://perezmeyer.com.ar/" title="Solo sé que se querer, que tengo Dios y tengo fe - planetdebian-en">Lisandro Damián Nicanor Pérez Meyer</a> <a href="https://perezmeyer.com.ar/blog/feeds/tags/planetdebian-en.atom.xml">(feed)</a></li> <li><a href="https://veronneau.org/" title="Louis-Philippe Véronneau">Louis-Philippe Véronneau</a> <a href="https://veronneau.org/feeds/languages/en.atom.xml">(feed)</a></li> <li><a href="https://kaeso.wordpress.com" title="planet-debian – Aquì estamos!">Luca Bruno</a> <a href="https://kaeso.wordpress.com/category/planet-debian/feed/atom/">(feed)</a></li> <li><a href="https://dktrkranz.wordpress.com" title="Planet Debian – Kranz Korner">Luca Falavigna</a> <a href="https://dktrkranz.wordpress.com/category/planet-debian/feed/atom/">(feed)</a></li> <li><a href="http://slackydeb.blogspot.com/search/label/gsoc" title="slackydeb">Luca Favatella</a> <a href="http://slackydeb.blogspot.com/feeds/posts/default/-/gsoc">(feed)</a></li> <li><a href="https://www.lucas-nussbaum.net/blog" title="PlanetDebian – Lucas Nussbaum's Blog">Lucas Nussbaum</a> <a href="https://www.lucas-nussbaum.net/blog/?feed=rss2&cat=13">(feed)</a></li> <li><a href="http://softwarelivre.org/lucianopc" title="Feed RSS do(a) Luciano Prestes Cavalcanti">Luciano Prestes Cavalcanti</a> <a href="http://softwarelivre.org/lucianopc/blog/feed">(feed)</a></li> <li><a href="https://blog.slyon.de" title="Debian – SlyBlog">Lukas Märdian</a> <a href="https://blog.slyon.de/category/debian/feed/">(feed)</a></li> <li><a href="https://blog.luke.wf/search/label/debian-planet" title="Luke W. Faraone">Luke Faraone</a> <a href="https://www.blogger.com/feeds/1354659632607599854/posts/default/-/debian-planet">(feed)</a></li> <li><a href="http://www.news.software.coop" title="Software Cooperative News » mjr">MJ Ray</a> <a href="https://mjr.towers.org.uk/blog/all.rss">(feed)</a></li> <li><a href="https://people.debian.org/~mafm/" title="Manuel A. Fernandez Montecelo :: Personal Debian page - planet-debian">Manuel A. Fernandez Montecelo</a> <a href="https://people.debian.org/~mafm/feeds/tag-planet-debian.atom.xml">(feed)</a></li> <li><a href="http://gonzo.dicp.de/~he/blog/" title="Marc's blog">Marc 'HE' Brockschmidt</a> <a href="http://gonzo.dicp.de/~he/blog/feeds/index.rss2">(feed)</a></li> <li><a href="https://mltplanet.livejournal.com/" title="Brezka">Marcela Tiznado</a> <a href="https://mltplanet.livejournal.com/data/rss">(feed)</a></li> <li><a href="https://blog.bofh.it/" title="Md at debian.org">Marco d'Itri</a> <a href="https://blog.bofh.it/debian/?format=atom">(feed)</a></li> <li><a href="https://siamezzze.github.io/" title="Maria Glukhova">Maria Glukhova</a> <a href="https://siamezzze.github.io/feed.xml">(feed)</a></li> <li><a href="https://blog.sirena.org.uk/" title="Technicalities">Mark Brown</a> <a href="https://blog.sirena.org.uk/rss/">(feed)</a></li> <li><a href="http://mlalic.blogspot.com/" title="Marko Lalic">Marko Lalic</a> <a href="http://mlalic.blogspot.com/feeds/posts/default?alt=rss">(feed)</a></li> <li><a href="https://gambaru.de/blog" title="planetdebian – gambaru.de">Markus Koschany</a> <a href="https://gambaru.de/blog/tag/planetdebian/feed/">(feed)</a></li> <li><a href="https://www.cyrius.com/" title="Martin Michlmayr">Martin Michlmayr</a> <a href="https://www.cyrius.com/blog/feed/">(feed)</a></li> <li><a href="https://blog.zobel.ftbfs.de/" title="zobel's blog">Martin Zobel-Helas</a> <a href="https://blog.zobel.ftbfs.de/feed.xml">(feed)</a></li> <li><a href="http://q-funk.blogspot.com/" title="Funkyware: ITCetera">Martin-Éric Racine</a> <a href="http://q-funk.blogspot.com/atom.xml">(feed)</a></li> <li><a href="https://www.mhatta.org/" title="Masayuki Hatta">Masayuki Hatta</a> <a href="https://www.mhatta.org/feeds/all.atom.xml">(feed)</a></li> <li><a href="https://mateusbellomo.wordpress.com" title="MateusBellomo">Mateus Bellomo</a> <a href="https://mateusbellomo.wordpress.com/feed/">(feed)</a></li> <li><a href="https://sathieu.wordpress.com" title="planetdebian – Sathieu: Computers and more">Mathieu Parent</a> <a href="https://sathieu.wordpress.com/tag/planetdebian/feed/">(feed)</a></li> <li><a href="https://matrix-team.pages.debian.net/blogue/" title="Matrix on Debian blog">Matrix on Debian blog</a> <a href="https://matrix-team.pages.debian.net/blogue/atom.xml">(feed)</a></li> <li><a href="https://mjg59.dreamwidth.org/" title="Matthew Garrett">Matthew Garrett</a> <a href="https://mjg59.dreamwidth.org/data/rss">(feed)</a></li> <li><a href="https://www.hezmatt.org/~mpalmer/blog/" title="Brane Dump">Matthew Palmer</a> <a href="https://www.hezmatt.org/~mpalmer/blog/rss.xml">(feed)</a></li> <li><a href="https://blog.tenstral.net" title="Debian – Ximions Blog">Matthias Klumpp</a> <a href="https://blog.tenstral.net/category/planet/planet-debian/feed">(feed)</a></li> <li><a href="https://smurf-debian.livejournal.com/" title="Debian Ramblings">Matthias Urlichs</a> <a href="https://smurf-debian.livejournal.com/data/rss">(feed)</a></li> <li><a href="https://matthieu.io" title="matthieu.io - Debian">Matthieu Caneill</a> <a href="https://matthieu.io/blog/feed/rss.debian.xml">(feed)</a></li> <li><a href="http://blog.dogguy.org/search/label/planetdebian" title="Crazy world...">Mehdi Dogguy</a> <a href="http://blog.dogguy.org/feeds/posts/default/-/planetdebian?alt=rss">(feed)</a></li> <li><a href="http://blog.alphascorpii.net/english" title="Comments from the rusty cage">Meike Reichle</a> <a href="http://blog.alphascorpii.net/english/index.rss">(feed)</a></li> <li><a href="https://melissawen.github.io/" title="Wen.onweb">Melissa Wen</a> <a href="https://melissawen.github.io/feed.xml">(feed)</a></li> <li><a href="http://mesutcaneng.blogspot.com/" title="Mesutcan Kurt's Blog Site">Mesutcan Kurt</a> <a href="http://mesutcaneng.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="https://abbbi.github.io//" title="Michael Ablassmeier">Michael Ablassmeier</a> <a href="https://abbbi.github.io/feed.xml">(feed)</a></li> <li><a href="https://ncommander.blogspot.com/" title="Notes from Underground ...">Michael Casadevall</a> <a href="https://www.blogger.com/feeds/4695702196537398257/posts/default">(feed)</a></li> <li><a href="http://www.credativ.us/blog/50" title="Michael Meskes's blog">Michael Meskes</a> <a href="https://www.credativ.com">(feed)</a></li> <li><a href="https://michael-prokop.at/blog" title="Debian – mikas blog">Michael Prokop</a> <a href="https://michael-prokop.at/blog/category/debian/feed/">(feed)</a></li> <li><a href="https://michael.stapelberg.ch/posts/tags/debian/" title="Michael Stapelbergs Website: posts tagged debian">Michael Stapelberg</a> <a href="https://michael.stapelberg.ch/posts/tags/debian/feed.xml">(feed)</a></li> <li><a href="https://mvogt.wordpress.com" title="Michael Vogt's blog">Michael Vogt</a> <a href="https://mvogt.wordpress.com/category/debian/feed/">(feed)</a></li> <li><a href="https://blog.cihar.com/archives/debian/" title="Michal Čihař's Weblog, posts tagged by Debian">Michal Čihař</a> <a href="https://blog.cihar.com/archives/debian/index.xml">(feed)</a></li> <li><a href="https://xerakko.livejournal.com/" title="Twin blog">Miguel Gea</a> <a href="https://xerakko.livejournal.com/data/rss">(feed)</a></li> <li><a href="http://www.debianslashrules.org//" title="debian/rules">Mike Beattie</a> <a href="http://www.debianslashrules.org/index.rss20">(feed)</a></li> <li><a href="https://sunweavers.net/blog/blog/1" title="sunweaver's blog">Mike Gabriel</a> <a href="https://sunweavers.net/blog/blog/1/feed">(feed)</a></li> <li><a href="https://glandium.org/blog" title="p.d.o – glandium.org">Mike Hommey</a> <a href="https://glandium.org/blog/?feed=rss2&cat=5&tag=en">(feed)</a></li> <li><a href="https://www.meebey.net/tags/planet-debian/" title="pages tagged planet-debian">Mirco Bauer</a> <a href="https://www.meebey.net/tags/planet-debian/index.rss">(feed)</a></li> <li><a href="https://morayallan.livejournal.com/" title="moray">Moray Allan</a> <a href="https://morayallan.livejournal.com/data/rss">(feed)</a></li> <li><a href="http://blog.daionet.gr.jp/knok-e" title="@knok blog-e">NOKUBI Takatsugu</a> <a href="http://blog.daionet.gr.jp/knok-e/feed/">(feed)</a></li> <li><a href="https://blog.halon.org.uk" title="Geek – Liberal Murmurs">Neil McGovern</a> <a href="https://blog.halon.org.uk/category/geek/feed/">(feed)</a></li> <li><a href="https://linux.codehelp.co.uk/" title="linux.codehelp.co.uk">Neil Williams</a> <a href="https://linux.codehelp.co.uk/blog.xml">(feed)</a></li> <li><a href="http://neuro.debian.net" title="NeuroDebian Insider">NeuroDebian</a> <a href="https://neuro.debian.net/feeds/for-debian-planet.xml">(feed)</a></li> <li><a href="http://nion.modprobe.de/blog/" title="nion's blog">Nico Golde</a> <a href="http://nion.modprobe.de/blog/feeds/index.rss1">(feed)</a></li> <li><a href="https://blog.olasd.eu" title="english – olasd's corner of the 'tubes">Nicolas Dandrimont</a> <a href="https://blog.olasd.eu/tag/english/feed">(feed)</a></li> <li><a href="https://people.debian.org/~nthykier/blog/" title="Things that I work on in Debian - pdo">Niels Thykier</a> <a href="https://people.debian.org/~nthykier/blog/feeds/pdo.atom.xml">(feed)</a></li> <li><a href="https://noah.meyerhans.us/categories/debian/" title="Noah Meyerhans - debian">Noah Meyerhans</a> <a href="https://noah.meyerhans.us/blog/categories/debian/index.xml">(feed)</a></li> <li><a href="https://elchipote.wordpress.com" title="planetdebian – el blog de n0rman">Norman García</a> <a href="https://elchipote.wordpress.com/category/planetdebian/feed/atom/">(feed)</a></li> <li><a href="http://www.milliways.fr/search/label/debian" title="Milliways">Obey Arthur Liu</a> <a href="http://www.milliways.fr/feeds/posts/default/-/debian">(feed)</a></li> <li><a href="https://gasuleg.github.io//" title="Gasuleg">Olivier Grégoire</a> <a href="https://gasuleg.github.io/feed.xml">(feed)</a></li> <li><a href="http://survex.com/~olly/blog" title="Olly's Blog">Olly Betts</a> <a href="https://survex.com/~olly/blog/index.atom">(feed)</a></li> <li><a href="http://ondrejcertik.blogspot.com/search/label/debian" title="Ondřej Čertík">Ondřej Čertík</a> <a href="http://ondrejcertik.blogspot.com/feeds/posts/default/-/debian">(feed)</a></li> <li><a href="http://goofying-with-debian.blogspot.com/" title="Goofying-with-Debian">Osamu Aoki</a> <a href="http://goofying-with-debian.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="https://optimizedbyotto.com/" title="Optimized by Otto">Otto Kekäläinen</a> <a href="https://optimizedbyotto.com/index.xml">(feed)</a></li> <li><a href="http://pstorralba.blogspot.com/search/label/tech" title="Pablo S. Torralba">Pablo S. Torralba</a> <a href="http://pstorralba.blogspot.com/feeds/posts/default/-/tech">(feed)</a></li> <li><a href="https://www.linux-dev.org" title="Blog of Patrick">Patrick Matthäi</a> <a href="https://www.linux-dev.org/feed/">(feed)</a></li> <li><a href="https://prezu.ca/" title="Patryk's blog">Patryk Cisek</a> <a href="https://prezu.ca/index.xml">(feed)</a></li> <li><a href="https://www.elpauer.org" title="Debian – elpauer">Pau Garcia i Quiles</a> <a href="https://www.elpauer.org/?cat=17&feed=rss2">(feed)</a></li> <li><a href="https://blog.pault.ag/" title="Paul Tagliamonte">Paul Tagliamonte</a> <a href="https://blog.pault.ag/rss">(feed)</a></li> <li><a href="https://k3xec.com/" title="K3XEC">Paul Tagliamonte</a> <a href="https://k3xec.com/index.xml?_cache_bust=1705936052">(feed)</a></li> <li><a href="https://notes.pault.ag/" title="Paul's Notes">Paul Tagliamonte</a> <a href="https://notes.pault.ag/index.xml">(feed)</a></li> <li><a href="http://bonedaddy.net/pabs3/log/" title="Log">Paul Wise</a> <a href="https://bonedaddy.net/pabs3/log/index.rss">(feed)</a></li> <li><a href="http://paul.luon.net" title="Paul's Web Pages">Paul van Tilburg</a> <a href="https://paul.luon.net//journal/tags/debian-planet/index.xml">(feed)</a></li> <li><a href="http://phls.com.br" title="Blog de Paulo Santana - Debian">Paulo Henrique de Lima Santana</a> <a href="https://phls.com.br/feed-planetdebian-en.xml">(feed)</a></li> <li><a href="https://pavitkaur05.github.io/post/" title="Posts by Pavit Kaur">Pavit Kaur</a> <a href="https://pavitkaur05.github.io/post/index.xml">(feed)</a></li> <li><a href="http://www.lupin.org.uk/blog" title="Disconnected Mutterings of a Random Geek">Pete Nuttall</a> <a href="http://www.lupin.org.uk/blog/computing/index.rss">(feed)</a></li> <li><a href="https://www.palfrader.org/blog/" title="weasel's blog">Peter Palfrader</a> <a href="https://www.palfrader.org/blog/index.rss">(feed)</a></li> <li><a href="http://www.hungry.com/~pere/blog/" title="Petter Reinholdtsen - Entries tagged english">Petter Reinholdtsen</a> <a href="http://www.hungry.com/~pere/blog/tags/english/english.rss">(feed)</a></li> <li><a href="http://wiki.hands.com/chezfil/" title="chezfil">Phil Hands</a> <a href="https://wiki.hands.com/chezfil/index.rss">(feed)</a></li> <li><a href="https://debblog.philkern.de/" title="Philipp Kern's Debian blog">Philipp Kern</a> <a href="https://www.blogger.com/feeds/5048890463514304208/posts/default?alt=rss">(feed)</a></li> <li><a href="https://qendresahoti.wordpress.com" title="Qendresa's creative stories">Qendresa Hoti</a> <a href="https://qendresahoti.wordpress.com/feed/">(feed)</a></li> <li><a href="http://blog.lot-of-stuff.info//Blog/debian-planet/" title="Blog/debian-planet">Rémi Vanicat</a> <a href="https://blog.lot-of-stuff.info/Blog/debian-planet/index.atom">(feed)</a></li> <li><a href="https://raju.dev/" title="site">Raju Devidas</a> <a href="https://raju.dev/rss/">(feed)</a></li> <li><a href="https://raphaelhertzog.com" title="apt-get install debian-wizard">Raphaël Hertzog</a> <a href="https://raphaelhertzog.com/tag/debian/feed/">(feed)</a></li> <li><a href="https://rgeissert.blogspot.com/" title="Raphael's blog">Raphael Geissert</a> <a href="https://rgeissert.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="https://ravidwivedi.in/posts/" title="Posts on Ravi's Blog">Ravi Dwivedi</a> <a href="https://ravidwivedi.in/posts/index.xml">(feed)</a></li> <li><a href="http://tauware.blogspot.com/" title="random thoughts of a F/OSS Developer...">Reinhard Tartler</a> <a href="http://tauware.blogspot.com/atom.xml">(feed)</a></li> <li><a href="https://rsip22.github.io/blog/" title="Renata's blog">Renata D'Avila</a> <a href="https://rsip22.github.io/blog/feeds/all.rss.xml">(feed)</a></li> <li><a href="https://reproducible-builds.org/blog/" title="reproducible-builds.org">Reproducible Builds</a> <a href="https://reproducible-builds.org/blog/index.rss">(feed)</a></li> <li><a href="https://diffoscope.org/" title="diffoscope">Reproducible Builds (diffoscope)</a> <a href="https://diffoscope.org/feed.xml">(feed)</a></li> <li><a href="https://rhonda.deb.at/blog/" title="Rhonda's Blog">Rhonda D'Vine</a> <a href="https://rhonda.deb.at/blog/index.planet">(feed)</a></li> <li><a href="https://mones.livejournal.com/" title="Ricardo Mones">Ricardo Mones</a> <a href="https://mones.livejournal.com/data/rss?tag=debian">(feed)</a></li> <li><a href="http://suihkulokki.blogspot.com/search/label/debian" title="suihkulokki rambling">Riku Voipio</a> <a href="http://suihkulokki.blogspot.com/feeds/posts/default/-/debian">(feed)</a></li> <li><a href="http://blog.floopily.org" title="Stories from the land of Rob">Rob Taylor</a> <a href="http://blog.floopily.org/feed/">(feed)</a></li> <li><a href="http://blog.mycre.ws/" title="Robert Edmonds' blog">Robert Edmonds</a> <a href="https://blog.mycre.ws/feeds/all.atom.xml">(feed)</a></li> <li><a href="https://ramcq.net" title="Robotic Tendencies">Robert McQueen</a> <a href="https://ramcq.net/feed/">(feed)</a></li> <li><a href="https://robertmh.wordpress.com" title="Thoughts of undetermined usefulness">Robert Millan</a> <a href="https://robertmh.wordpress.com/feed/">(feed)</a></li> <li><a href="https://siqueira.tech/" title="Siqueira">Rodrigo Siqueira</a> <a href="https://siqueira.tech/feed.xml">(feed)</a></li> <li><a href="http://cynic.cc/blog//tags/debian/" title="pages tagged debian">Rogério Brito</a> <a href="http://cynic.cc/blog/tags/debian/index.rss">(feed)</a></li> <li><a href="http://roland.entierement.nu/categories/en.html" title="In English">Roland Mas</a> <a href="http://roland.entierement.nu/categories/en.rss">(feed)</a></li> <li><a href="https://rperier.blogspot.com/search/label/debian" title="Romain Perier's blog">Romain Perier</a> <a href="https://rperier.blogspot.com/feeds/posts/default/-/debian">(feed)</a></li> <li><a href="https://rossgammon68.wordpress.com" title="Planet Debian – Ross Gammon's Blog">Ross Gammon</a> <a href="https://rossgammon68.wordpress.com/category/open-source/debian/planet-debian/feed/">(feed)</a></li> <li><a href="https://ruby-team.pages.debian.net/" title="The Ruby Team Pages">Ruby Team</a> <a href="https://ruby-team.pages.debian.net/feed.xml">(feed)</a></li> <li><a href="" title="">Rudy Godoy</a> <a href="https://blog.stone-head.org/category/debian/feed/">(feed)</a></li> <li><a href="https://www.eyrie.org/~eagle/" title="Eagle's Path">Russ Allbery</a> <a href="https://www.eyrie.org/~eagle/journal/index.rss">(feed)</a></li> <li><a href="https://etbe.coker.com.au" title="etbe – Russell Coker">Russell Coker</a> <a href="https://etbe.coker.com.au/feed/">(feed)</a></li> <li><a href="https://rak.ac/feeds/planet-debian.xml" title="Ryan Kavanagh's /dev/brain">Ryan Kavanagh</a> <a href="https://rak.ac/feeds/planet-debian.xml">(feed)</a></li> <li><a href="https://blog.sahilister.in/" title="sahilister's Reimagined Doodle">Sahil Dhiman</a> <a href="https://blog.sahilister.in/index.xml">(feed)</a></li> <li><a href="https://hartmans.dreamwidth.org/" title="Sam Hartman">Sam Hartman</a> <a href="https://hartmans.dreamwidth.org/data/atom">(feed)</a></li> <li><a href="https://samueloph.dev" title="Samuel Henrique (samueloph)">Samuel Henrique</a> <a href="https://samueloph.dev/atom.xml">(feed)</a></li> <li><a href="https://blog.sandroknauss.de/" title="Decrypted Mind: Articles About Debian">Sandro Knauß</a> <a href="https://blog.sandroknauss.de/categories/debian/feed.xml">(feed)</a></li> <li><a href="http://sandrotosi.blogspot.com/" title="Sandro Tosi">Sandro Tosi</a> <a href="http://feeds.feedburner.com/SandroTosi">(feed)</a></li> <li><a href="http://blog.manty.net/search/label/Debian" title="manty's blog">Santiago García Mantiñán</a> <a href="http://blog.manty.net/feeds/posts/default/-/Debian">(feed)</a></li> <li><a href="http://satyamz.github.io/" title="Category: Debian | Satyam Zode">Satyam Zode</a> <a href="https://satyamz.github.io/blog/categories/debian/atom.xml">(feed)</a></li> <li><a href="https://www.scarlettgatelymoore.dev" title="Open Source Software – Scarlett Gately Moore">Scarlett Gately Moore</a> <a href="https://www.scarlettgatelymoore.dev/category/open-source-software/feed/">(feed)</a></li> <li><a href="https://skitterman.wordpress.com" title="Debian – ScottK might have something to say …">Scott Kitterman</a> <a href="https://skitterman.wordpress.com/category/Debian/feed/">(feed)</a></li> <li><a href="https://spwhitton.name//blog/" title="Notes from the Library">Sean Whitton</a> <a href="https://spwhitton.name/blog/index.rss">(feed)</a></li> <li><a href="http://shnatsel.blogspot.com/search/label/planet-debian" title="Shnatsel&#39;s Old Blog">Sergey Davidoff</a> <a href="http://shnatsel.blogspot.com/feeds/posts/default/-/planet-debian">(feed)</a></li> <li><a href="https://blog.sergiodj.net/tags/debian/" title="Debian on Yet Another Me">Sergio Durigan Junior</a> <a href="https://blog.sergiodj.net/tags/debian/atom.xml">(feed)</a></li> <li><a href="https://blogops.mixinet.net/" title="Mixinet BlogOps">Sergio Talens-Oliag</a> <a href="https://blogops.mixinet.net/index.xml">(feed)</a></li> <li><a href="https://sandyleo26.wordpress.com" title="Sandyleo26’s Blog">Sha Liu</a> <a href="https://sandyleo26.wordpress.com/feed/">(feed)</a></li> <li><a href="https://blog.shanky.dev/" title="Shanky's Brainchild">Shashank Kumar</a> <a href="https://blog.shanky.dev/feeds/all.atom.xml">(feed)</a></li> <li><a href="http://bloc.eurion.net" title="Planet Debian – eurion.net">Siegfried Gevatter</a> <a href="https://bloc.eurion.net/archives/category/debian-planet/feed/">(feed)</a></li> <li><a href="http://sim590.github.io/" title="Simon Désaulniers">Simon Désaulniers</a> <a href="https://sim590.github.io/index.xml">(feed)</a></li> <li><a href="http://www.earth.li/~huggie/blog" title="Simon Huggins's blog">Simon Huggins</a> <a href="https://www.earth.li/~huggie/blog/tech/debian/planet/index.atom">(feed)</a></li> <li><a href="https://blog.josefsson.org" title="Simon Josefsson's blog">Simon Josefsson</a> <a href="https://blog.josefsson.org/feed/">(feed)</a></li> <li><a href="https://sfllaw.livejournal.com/" title="Simon Law’s Journal">Simon Law</a> <a href="https://sfllaw.livejournal.com/data/rss?tag=p.d.o">(feed)</a></li> <li><a href="http://smcv.pseudorandom.co.uk/" title="Background noise">Simon McVittie</a> <a href="https://smcv.pseudorandom.co.uk/feed.atom">(feed)</a></li> <li><a href="https://medium.com/@tsimonq2?source=rss-abe8950a00ea------2" title="Stories by Simon Quigley on Medium">Simon Quigley</a> <a href="https://medium.com/@tsimonq2/feed">(feed)</a></li> <li><a href="http://sjoerd.luon.net/blog/" title="Sjoerd Simons' blog">Sjoerd Simons</a> <a href="http://sjoerd.luon.net/blog/index.atom">(feed)</a></li> <li><a href="http://sonnenburgs.de/soeren/category/blog/" title="RSS feed">Soeren Sonnenburg</a> <a href="https://sonnenburgs.de/soeren/category/blog/feed">(feed)</a></li> <li><a href="http://home-sorina.blogspot.com/search/label/Debian" title="/home/sorina">Sorina Sandu</a> <a href="http://home-sorina.blogspot.com/feeds/posts/default/-/Debian">(feed)</a></li> <li><a href="http://upsilon.cc/~zack/blog/planet-debian/" title="blog/planet-debian">Stefano Zacchiroli</a> <a href="https://upsilon.cc/~zack/blog/planet-debian/index.rss">(feed)</a></li> <li><a href="https://jod.al" title="jod.al - debian">Stein Magnus Jodal</a> <a href="https://jod.al/tags/debian/atom.xml">(feed)</a></li> <li><a href="http://blog.sesse.net/" title="Steinar H. Gunderson">Steinar H. Gunderson</a> <a href="https://blog.sesse.net/blog/tech/?flav=rss">(feed)</a></li> <li><a href="https://stephan.lachnit.xyz/tags/debian/" title="Debian on Blog">Stephan Lachnit</a> <a href="https://stephan.lachnit.xyz/tags/debian/index.xml">(feed)</a></li> <li><a href="https://blog.steve.fi/" title="Steve Kemp's Blog">Steve Kemp</a> <a href="https://blog.steve.fi/index.rss">(feed)</a></li> <li><a href="http://web.dodds.net/~vorlon/wiki/blog/" title="blog">Steve Langasek</a> <a href="https://web.dodds.net/~vorlon/wiki/blog/index.rss">(feed)</a></li> <li><a href="https://blog.einval.com" title="Steve's blog">Steve McIntyre</a> <a href="https://blog.einval.com/index.rss">(feed)</a></li> <li><a href="https://pusling.com/blog" title="english – Blog :: Sune Vuorela">Sune Vuorela</a> <a href="https://pusling.com/blog/?feed=rss2&cat=3">(feed)</a></li> <li><a href="http://sven.stormbind.net/blog/" title="a blog">Sven Hoexter</a> <a href="https://sven.stormbind.net/blog/index.rss">(feed)</a></li> <li><a href="https://blog.beuc.net/tags/planet_debian/" title="pages tagged planet debian">Sylvain Beucler</a> <a href="https://blog.beuc.net/tags/planet_debian/index.atom">(feed)</a></li> <li><a href="http://sylvain.le-gall.net/blog/index.php?" title="Blog of Sylvain Le Gall">Sylvain Le Gall</a> <a href="https://sylvain.le-gall.net/blog/index.php?feed/atom">(feed)</a></li> <li><a href="https://sylvestre.ledru.info/blog/" title="Sylvestre's blog - Catégorie: "Debian"">Sylvestre Ledru</a> <a href="https://sylvestre.ledru.info/blog/xmlsrv/rss2.php?blog=5&cat=155">(feed)</a></li> <li><a href="https://taavi.wtf/posts/" title="Blog on Taavi Väänänen">Taavi Väänänen</a> <a href="https://taavi.wtf/posts/index.xml">(feed)</a></li> <li><a href="https://tanguy.ortolo.eu/blog/categorie2/debian" title="Tanguy Ortolo - Debian">Tanguy Ortolo</a> <a href="https://tanguy.ortolo.eu/blog/planet/debian.rss">(feed)</a></li> <li><a href="https://writefreely.debian.social/taowa/" title="taowa r.">Taowa</a> <a href="https://writefreely.debian.social/taowa/feed">(feed)</a></li> <li><a href="https://cascardo.eti.br/tags/debian/" title="pages tagged debian">Thadeu Lima de Souza Cascardo</a> <a href="https://cascardo.eti.br/tags/debian/index.atom">(feed)</a></li> <li><a href="https://theppitak.livejournal.com/" title="Theppitak Karoonboonyanan">Theppitak Karoonboonyanan</a> <a href="https://theppitak.livejournal.com/data/rss">(feed)</a></li> <li><a href="http://gsoc.sitedethib.com/" title="Bits from a GSoC student">Thibaut Girka</a> <a href="https://gsoc.sitedethib.com/index.rss">(feed)</a></li> <li><a href="https://teejeejee.livejournal.com/" title="teejeejee">Thomas Girard</a> <a href="https://teejeejee.livejournal.com/data/rss?tag=debian">(feed)</a></li> <li><a href="http://thomas.goirand.fr/blog" title="Zigo's blog">Thomas Goirand</a> <a href="http://thomas.goirand.fr/blog/?feed=rss2">(feed)</a></li> <li><a href="http://blog.fai-project.org/" title="FAI (Fully Automatic Installation) / Plan your Installation and FAI installs your Plan">Thomas Lange</a> <a href="https://blog.fai-project.org/index.rss">(feed)</a></li> <li><a href="http://blog.alteholz.eu" title="planetdebian – blog.alteholz.eu">Thorsten Alteholz</a> <a href="http://blog.alteholz.eu/tag/planetdebian/feed/">(feed)</a></li> <li><a href="http://tiago.acaia.ca/" title="❤ (planet-debian)">Tiago Bortoletto Vaz</a> <a href="https://qa.debian.org/developer.php?login=tiago&comaint=yes">(feed)</a></li> <li><a href="https://tianon.github.io/" title="Tianon's Ramblings">Tianon Gravi</a> <a href="https://ram.tianon.xyz/atom.xml">(feed)</a></li> <li><a href="https://retout.co.uk/" title="Tim Retout">Tim Retout</a> <a href="https://retout.co.uk/index.xml">(feed)</a></li> <li><a href="https://losca.blogspot.com/search/label/debian" title="Losca">Timo Jyrinki</a> <a href="https://losca.blogspot.com/feeds/posts/default/-/debian?alt=rss">(feed)</a></li> <li><a href="https://ttroxell.livejournal.com/" title="Work Blog">Todd Troxell</a> <a href="https://ttroxell.livejournal.com/data/rss">(feed)</a></li> <li><a href="https://err.no/personal/blog/" title="Blogs on Here be dragons">Tollef Fog Heen</a> <a href="https://err.no/personal/blog/index.xml">(feed)</a></li> <li><a href="http://dangel.im/blog/" title="Ulrichs blog - Debian">Ulrich Dangel</a> <a href="https://dangel.im/blog/debian.xml">(feed)</a></li> <li><a href="https://the.curlybracket.net/" title="curlybracket">Ulrike Uhlig</a> <a href="https://the.curlybracket.net/atom.xml">(feed)</a></li> <li><a href="https://urvikagola.wordpress.com" title="Urvika Gola">Urvika Gola</a> <a href="https://urvikagola.wordpress.com/feed/">(feed)</a></li> <li><a href="https://utkarsh2102.org/" title="utkarsh2102">Utkarsh Gupta</a> <a href="https://utkarsh2102.org/index.xml">(feed)</a></li> <li><a href="https://blog.kleine-koenig.org/ukl/" title="ukl's blog">Uwe Kleine-König</a> <a href="https://blog.kleine-koenig.org/ukl/feeds/all.atom.xml">(feed)</a></li> <li><a href="http://www.spectranaut.cc" title="Spectranaut (Valerie Young)">Valerie Young</a> <a href="https://spectranaut.cc/?tag=debian&feed=rss2">(feed)</a></li> <li><a href="https://blog.trueelena.org" title="Valhalla's things">Valhalla's Things</a> <a href="https://blog.trueelena.org/atom.xml">(feed)</a></li> <li><a href="https://copyninja.in/" title="Random Ramblings">Vasudev Kamath</a> <a href="https://copyninja.in/feeds/all.atom.xml">(feed)</a></li> <li><a href="https://vincent.bernat.ch/en" title="Vincent Bernat">Vincent Bernat</a> <a href="https://vincent.bernat.ch/en/blog/atom.xml">(feed)</a></li> <li><a href="https://vince-debian.blogspot.com/" title="YANUB: yet another (nearly) useless blog">Vincent Fourmond</a> <a href="https://vince-debian.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="http://vincentsanders.blogspot.com/" title="Vincents Random Waffle">Vincent Sanders</a> <a href="http://vincentsanders.blogspot.com/feeds/posts/default">(feed)</a></li> <li><a href="https://billblough.net/" title="Bill's Web Log - FLOSS">William (Bill) Blough</a> <a href="https://billblough.net/feeds/floss.atom.xml">(feed)</a></li> <li><a href="https://grep.be/blog//pd/" title="pd">Wouter Verhelst</a> <a href="https://grep.be/blog/pd/index.rss">(feed)</a></li> <li><a href="https://appaji.livejournal.com/" title="Morsels of life!">Y Giridhar Appaji Nag</a> <a href="https://appaji.livejournal.com/data/atom">(feed)</a></li> <li><a href="http://www.corsac.net/?cat=3" title="Corsac.net - Debian">Yves-Alexis Perez</a> <a href="https://www.corsac.net/rss.php?cat=debian">(feed)</a></li> <li><a href="https://zgrimshell.github.io/" title="i.am.z.grim.shell">Zlatan Todorić</a> <a href="https://zgrimshell.github.io/rss.xml">(feed)</a></li> <li><a href="https://people.debian.org/~intrigeri/blog/" title="intrigeri's blog">intrigeri</a> <a href="https://people.debian.org/~intrigeri/blog/index.rss">(feed)</a></li> <li><a href="https://vulns.xyz" title="vulns.xyz">kpcyrd</a> <a href="https://vulns.xyz/feed.xml">(feed)</a></li> <li><a href="https://loldebian.wordpress.com" title="loldebian: i can has a rc bug?">loldebian - Can I has a RC bug?</a> <a href="https://loldebian.wordpress.com/feed/">(feed)</a></li> </ul> </div> </body> </html>