In July 2024, NASA posted an article titled NASA Has Pride Across the
Universe featuring a pride flag by Rachel Lense where each color band is made
up of images from across NASA. Today is the annual International Transgender
Day of
Visibility.
The original NASA article from last year has
since been taken offline. But the heroes from archive.org still carry a copy
which I now archived myself together
with the other source images. Here is NASA s pride flag in all its glory:
Southern Fried Science has an article about the
flag.
The original 4000x2547 TIFF image was stored not by archive.org but the PNG
version in the same resolution can be downloaded
here or by
clicking on the image.
A new release 0.1.8 of RcppZiggurat
is now on the CRAN network for
R, following up on the 0.1.7
release last week which was the first release in four and a half
years.
The RcppZiggurat
package updates the code for the Ziggurat
generator by Marsaglia and
others which provides very fast draws from a Normal (or Exponential)
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 GSL, QuantLib and Gretl all of which are still
way faster than the default Normal generator in R (which is of course of
higher code complexity).
This release switches the vignette to the standard trick of premaking
it as a pdf and including it in a short Sweave document that imports it
via pdfpages; this minimizes build-time dependencies on
other TeXLive components. It also incorporates a change contributed by
Tomas to rely on the system build of the GSL on Windows as well if
Rtools 42 or later is found. No other changes.
The NEWS file entry below lists all changes.
Changes in version 0.1.8
(2025-03-30)
The vignette is now premade and rendered as Rnw via pdfpage to
minimize the need for TeXLive package at build / install time
(Dirk)
Windows builds now use the GNU GSL when Rtools is 42 or later
(Tomas Kalibera in #25)
As I write this in March 2025, there is a lot of confusion about Signal messenger due to the recent news of people using Signal in government, and subsequent leaks.
The short version is: there was no problem with Signal here. People were using it because they understood it to be secure, not the other way around.
Both the government and the Electronic Frontier Foundation recommend people use Signal. This is an unusual alliance, and in the case of the government, was prompted because it understood other countries had a persistent attack against American telephone companies and SMS traffic.
So let s dive in. I ll cover some basics of what security is, what happened in this situation, and why Signal is a good idea.
This post isn t for programmers that work with cryptography every day. Rather, I hope it can make some of these concepts accessible to everyone else.
What makes communications secure?
When most people are talking about secure communications, they mean some combination of these properties:
Privacy - nobody except the intended recipient can decode a message.
Authentication - guarantees that the person you are chatting with really is the intended recipient.
Ephemerality - preventing a record of the communication from being stored. That is, making it more like a conversation around the table than a written email.
Anonymity - keeping your set of contacts to yourself and even obfuscating the fact that communications are occurring.
If you think about it, most people care the most about the first two. In fact, authentication is a key part of privacy. There is an attack known as man in the middle in which somebody pretends to be the intended recipient. The interceptor reads the messages, and then passes them on to the real intended recipient. So we can t really have privacy without authentication.
I ll have more to say about these later. For now, let s discuss attack scenarios.
What compromises security?
There are a number of ways that security can be compromised. Let s think through some of them:
Communications infrastructure snooping
Let s say you used no encryption at all, and connected to public WiFi in a coffee shop to send your message. Who all could potentially see it?
The owner of the coffee shop s WiFi
The coffee shop s Internet provider
The recipient s Internet provider
Any Internet providers along the network between the sender and the recipient
Any government or institution that can compel any of the above to hand over copies of the traffic
Any hackers that compromise any of the above systems
Back in the early days of the Internet, most traffic had no encryption. People were careful about putting their credit cards into webpages and emails because they knew it was easy to intercept them. We have been on a decades-long evolution towards more pervasive encryption, which is a good thing.
Text messages (SMS) follow a similar path to the above scenario, and are unencrypted. We know that all of the above are ways people s texts can be compromised; for instance, governments can issue search warrants to obtain copies of texts, and China is believed to have a persistent hack into western telcos. SMS fails all four of our attributes of secure communication above (privacy, authentication, ephemerality, and anonymity).
Also, think about what information is collected from SMS and by who. Texts you send could be retained in your phone, the recipient s phone, your phone company, their phone company, and so forth. They might also live in cloud backups of your devices. You only have control over your own phone s retention.
So defenses against this involve things like:
Strong end-to-end encryption, so no intermediate party even the people that make the app can snoop on it.
Using strong authentication of your peers
Taking steps to prevent even app developers from being able to see your contact list or communication history
You may see some other apps saying they use strong encryption or use the Signal protocol. But while they may do that for some or all of your message content, they may still upload your contact list, history, location, etc. to a central location where it is still vulnerable to these kinds of attacks.
When you think about anonymity, think about it like this: if you send a letter to a friend every week, every postal carrier that transports it even if they never open it or attempt to peak inside will be able to read the envelope and know that you communicate on a certain schedule with that friend. The same can be said of SMS, email, or most encrypted chat operators. Signal s design prevents it from retaining even this information, though nation-states or ISPs might still be able to notice patterns (every time you send something via Signal, your contact receives something from Signal a few milliseconds later). It is very difficult to provide perfect anonymity from well-funded adversaries, even if you can provide very good privacy.
Device compromise
Let s say you use an app with strong end-to-end encryption. This takes away some of the easiest ways someone could get to your messages. But it doesn t take away all of them.
What if somebody stole your phone? Perhaps the phone has a password, but if an attacker pulled out the storage unit, could they access your messages without a password? Or maybe they somehow trick or compel you into revealing your password. Now what?
An even simpler attack doesn t require them to steal your device at all. All they need is a few minutes with it to steal your SIM card. Now they can receive any texts sent to your number - whether from your bank or your friend. Yikes, right?
Signal stores your data in an encrypted form on your device. It can protect it in various ways. One of the most important protections is ephemerality - it can automatically delete your old texts. A text that is securely erased can never fall into the wrong hands if the device is compromised later.
An actively-compromised phone, though, could still give up secrets. For instance, what if a malicious keyboard app sent every keypress to an adversary? Signal is only as secure as the phone it runs on but still, it protects against a wide variety of attacks.
Untrustworthy communication partner
Perhaps you are sending sensitive information to a contact, but that person doesn t want to keep it in confidence. There is very little you can do about that technologically; with pretty much any tool out there, nothing stops them from taking a picture of your messages and handing the picture off.
Environmental compromise
Perhaps your device is secure, but a hidden camera still captures what s on your screen. You can take some steps against things like this, of course.
Human error
Sometimes humans make mistakes. For instance, the reason a reporter got copies of messages recently was because a participant in a group chat accidentally added him (presumably that participant meant to add someone else and just selected the wrong name). Phishing attacks can trick people into revealing passwords or other sensitive data. Humans are, quite often, the weakest link in the chain.
Protecting yourself
So how can you protect yourself against these attacks? Let s consider:
Use a secure app like Signal that uses strong end-to-end encryption where even the provider can t access your messages
Keep your software and phone up-to-date
Be careful about phishing attacks and who you add to chat rooms
Be aware of your surroundings; don t send sensitive messages where people might be looking over your shoulder with their eyes or cameras
There are other methods besides Signal. For instance, you could install GnuPG (GPG) on a laptop that has no WiFi card or any other way to connect it to the Internet. You could always type your messages on that laptop, encrypt them, copy the encrypted text to a floppy disk (or USB device), take that USB drive to your Internet computer, and send the encrypted message by email or something. It would be exceptionally difficult to break the privacy of messages in that case (though anonymity would be mostly lost). Even if someone got the password to your secure laptop, it wouldn t do them any good unless they physically broke into your house or something. In some ways, it is probably safer than Signal. (For more on this, see my article How gapped is your air?)
But, that approach is hard to use. Many people aren t familiar with GnuPG. You don t have the convenience of sending a quick text message from anywhere. Security that is hard to use most often simply isn t used. That is, you and your friends will probably just revert back to using insecure SMS instead of this GnuPG approach because SMS is so much easier.
Signal strikes a unique balance of providing very good security while also being practical, easy, and useful. For most people, it is the most secure option available.
Signal is also open source; you don t have to trust that it is as secure as it says, because you can inspect it for yourself. Also, while it s not federated, I previously addressed that.
Government use
If you are a government, particularly one that is highly consequential to the world, you can imagine that you are a huge target. Other nations are likely spending billions of dollars to compromise your communications. Signal itself might be secure, but if some other government can add spyware to your phones, or conduct a successful phishing attack, you can still have your communications compromised.
I have no direct knowledge, but I think it is generally understood that the US government maintains communications networks that are entirely separate from the Internet and can only be accessed from secure physical locations and secure rooms. These can be even more secure than the average person using Signal because they can protect against things like environmental compromise, human error, and so forth. The scandal in March of 2025 happened because government employees were using Signal rather than official government tools for sensitive information, had taken advantage of Signal s ephemerality (laws require records to be kept), and through apparent human error had directly shared this information with a reporter. Presumably a reporter would have lacked access to the restricted communications networks in the first place, so that wouldn t have been possible.
This doesn t mean that Signal is bad. It just means that somebody that can spend billions of dollars on security can be more secure than you. Signal is still a great tool for people, and in many cases defeats even those that can spend lots of dollars trying to defeat it.
And remember - to use those restricted networks, you have to go to specific rooms in specific buildings. They are still not as convenient as what you carry around in your pocket.
Conclusion
Signal is practical security. Do you want phone companies reading your messages? How about Facebook or X? Have those companies demonstrated that they are completely trustworthy throughout their entire history?
I say no. So, go install Signal. It s the best, most practical tool we have.
This post is also available on my website, where it may be periodically updated.
dmidecode grep -A8 ^System Information
tells me that the Manufacturer is HP and Product Name is OMEN Transcend Gaming Laptop 14-fb0xxx
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.
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.
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:
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.
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.
The other day, I noted that the emacs integration with debputy stopped working.
After debugging for a while, I realized that emacs no longer sent the didOpen
notification that is expected of it, which confused debputy. At this point, I was
already several hours into the debugging and I noted there was some discussions on
debian-devel about emacs and byte compilation not working. So I figured I would
shelve the emacs problem for now.
But I needed an LSP capable editor and with my vi skills leaving much to be desired,
I skipped out on vim-youcompleteme. Instead, I pulled out kate, which I had not
been using for years. It had LSP support, so it would fine, right?
Well, no. Turns out that debputy LSP support had some assumptions that worked for
emacs but not kate. Plus once you start down the rabbit hole, you stumble on
things you missed previously.
Getting started
First order of business was to tell kate about debputy. Conveniently, kate 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.
Yesterday, I opened an MR against upstream to have the configuration added
(https://invent.kde.org/utilities/kate/-/merge_requests/1748) and they already merged it.
Today, I then filed a wishlist against kate in Debian to have the Debian maintainers
cherry-pick it, so it works out of the box for Trixie (https://bugs.debian.org/1099876).
So far so good.
Inlay hint woes
Since July (2024), debputy has support for Inlay hints. 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.
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.
In debputy, I have been using the Inlay hints to show inherited fields in
debian/control. As an example, if you have a definition like:
Source: foo-src
Section: devel
Priority: optional
Package: foo-bin
Architecture: any
Then foo-bin inherits the Section and Priority field since it does not supply
its own. Previously, debputy would that by injecting the fields themselves and their
value just below the Package field as if you had typed them out directly. The editor
always renders Inlay hints distinctly from regular text, so there was no risk of
confusion and it made the text look like a valid debian/control file end to end. The
result looked something like:
With the second instances of Section and Priority being rendered differently than
its surrendering (usually faded or colorlessly).
Unfortunately, kate did not like injecting Inlay hints with a newline in them,
which was needed for this trick. Reading into the LSP specs, it says nothing about
multi-line Inlay hints being a thing and I figured I would see this problem again
with other editors if I left it be.
I ended up changing the Inlay hints to be placed at the end of the Package field
and then included surrounding () for better visuals. So now, it looks like:
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
Inlay hint for the Homepage field. It takes too much space and I have yet to
meet someone missing it in the binary stanza.
If you have any better ideas for how to render it, feel free to reach out to me.
Spurious completion and hover
As I was debugging the Inlay hints, I wanted to do a quick restart of debputy after
each fix. Then I would trigger a small change to the document to ensure kate would
request an update from debputy to render the Inlay hints with the new code.
The full outgoing payloads are sent via the logs to the client, so it was really about
minimizing which LSP requests are sent to debputy. Notably, two cases would flood the
log:
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.
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 kate.
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.
Unfortunately for me, debputy 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 \#, so they are all discarded.
But it was pretty annoying for the debugging, so now debputy has been told to explicitly
stop these requests early on comment lines.
Hover docs for packages
I added a feature in debputy where you can hover over package names in your relationship
fields (such as Depends) and debputy will render a small snippet about it based on
data from your local APT cache.
This doc is then handed to the editor and tagged as markdown provided the editor supports
markdown rendering. Both emacs and kate support markdown. However, not all
markdown renderings are equal. Notably, emacs's rendering does not reformat the text
into paragraphs. In a sense, emacs rendering works a bit like <pre>...</pre> except
it does a bit of fancy rendering inside the <pre>...</pre>.
On the other hand, kate seems to convert the markdown 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 markdown. A Foo<newline>Bar is treated as one "paragraph" (<p>...</p>) and the HTML
render happily renders this as single line Foo Bar provided there is sufficient width to
do so.
A couple of extra newlines made wonders for the kate 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.
Making quickfixes available in kate
Quickfixes are treated as generic code actions in the LSP specs. Each code action has a "type"
(kind in the LSP lingo), which enables the editor to group the actions accordingly or
filter by certain types of code actions.
The design in the specs leads to the following flow:
The LSP server provides the editor with diagnostics (there are multiple ways to trigger
this, so we will keep this part simple).
The editor renders them to the user and the user chooses to interact with one of them.
The interaction makes the editor asks the LSP server, which code actions are available
at that location (optionally with filter to only see quickfixes).
The LSP server looks at the provided range and is expected to return the relevant
quickfixes here.
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.
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.
The editor can provide support for remembering a data 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.
All the quickfix logic in debputy so far has hinged on both of these two features.
As life would have it, kate provides neither of them.
Which meant I had to teach debputy 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, debputy logic is now always used rather than relying on the editor support
when present.
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.
Making the quickfixes actually work
With all of that, kate would show the quickfixes for diagnostics from debputy and you could
use them too. However, they would always apply twice with suboptimal outcome as a result.
The LSP spec has multiple ways of defining what need to be changed in response to activating a
code action. In debputy, all edits are currently done via the WorkspaceEdit type. It
has two ways of defining the changes. Either via changes or documentChanges with
documentChanges being the preferred one if both parties support this.
I originally read that as I was allowed to provide both and the editor would pick the one it
preferred. However, after seeing kate blindly use both when they are present, I reviewed
the spec and it does say "The edit should either provide changes or documentChanges",
so I think that one is on me.
None of the changes in debputy currently require documentChanges, so I went with just
using changes for now despite it not being preferred. I cannot figure
out the logic of whether an editor supports documentChanges. As I read the notes for this
part of the spec, my understanding is that kate does not announce its support for
documentChanges but it clearly uses them when present. Therefore, I decided to keep it
simple for now until I have time to dig deeper.
Remaining limitations with kate
There is one remaining limitation with kate that I have not yet solved. The kate
program uses KSyntaxHighlighting for its language detection, which in turn is the
basis for which LSP server is assigned to a given document.
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
debian/control vs. debian/tests/control or debian/rules or
debian/upstream/metadata makes things awkward a best.
Concretely, the syntax engine cannot tell debian/control from debian/tests/control as
they use the same basename. Fortunately, the syntax is close enough to work for both and
debputy is set to use filename based lookups, so this case works well enough.
However, for debian/rules and debian/upstream/metadata, my understanding is that if
I assign these in the syntax engine as Debian files, these rules will also trigger for any
file named foo.rules or bar.metadata. 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 kate for now.
The current LSP configuration in kate 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, kate has a built-in language server for YAML and
debputy does nothing for a generic YAML document. However, adding YAML as a supported
language for debputy would cause conflict and regressions for users that are already
happy with their generic YAML language server from kate.
So there are certainly still work to be done. If you are good with KSyntaxHighlighting
and know how to solve some of this, I hope you will help me out.
Changes unrelated to kate
While I was working on debputy, I also added some other features that I want to mention.
The debputy lint 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).
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 debian/control, then
debputy will add a diagnostic to the second occurrence. The related information
for that diagnostic would provide the position of the first occurrence.
This should make it easier to find the source of the conflict in the cases where
debputy provides it. Let me know if you are missing it for certain diagnostics.
The diagnostics analysis of debian/control 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.
Closing
I am glad I tested with kate to weed out most of these issues in time before
the freeze. The Debian freeze will start within a week from now. Since debputy
is a part of the toolchain packages it will be frozen from there except for
important bug fixes.
Welcome to the second report in 2025 from the Reproducible Builds project. 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 Contribute page on our website.
Table of contents:
Reproducible Builds at FOSDEM 2025
Similar to last year s event, there was considerable activity regarding Reproducible Builds at FOSDEM 2025, held on on 1st and 2nd February this year in Brussels, Belgium. We count at least four talks related to reproducible builds. (You can also read our news report from last year s event in which Holger Levsen presented in the main track.)
Jelle van der Waa, Holger Levsen and kpcyrd presented in the Distributions track on A Tale of several distros joining forces for a common goal. 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 slides of this talk are available to view, as is the full video (30m02s). The talk was also discussed on Hacker News.
Zbigniew J drzejewski-Szmek presented in the ever-popular Python track a on Rewriting .pyc files for fun and reproducibility, 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 slides of this talk are available, as is the full video (28m32s).
In the Nix and NixOS track, Julien Malka presented on the Saturday asking How reproducible is NixOS: We know that the NixOS ISO image is very close to be perfectly reproducible thanks to reproducible.nixos.org, 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 blog and article on the results.
Lastly, Simon Tournier presented in the Open Research track on the confluence of GNU Guix and Software Heritage: Source Code Archiving to the Rescue of Reproducible Deployment. 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 slides for the talk are available, as is the full video (23m17s).
Reproducible Builds at PyCascades 2025
Vagrant Cascadian presented at this year s PyCascades conference which was held on February 8th and 9th February in Portland, OR, USA. PyCascades is a regional instance of PyCon held in the Pacific Northwest. Vagrant s talk, entitled Re-Py-Ducible Builds caught the audience s attention with the following abstract:
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.
reproduce.debian.net updates
The last few months have seen the introduction of reproduce.debian.net. Announced first at the recent Debian MiniDebConf in Toulouse, reproduce.debian.net is an instance of rebuilderd operated by the Reproducible Builds project.
Powering this work is rebuilderd, our server which monitors the official package repositories of Linux distributions and attempt to reproduce the observed results there. This month, however, Holger Levsen:
Split packages that are not specific to any architecture away from amd64.reproducible.debian.net service into a new all.reproducible.debian.net page.
Increased the number of riscv64 nodes to a total of 4, and added a new amd64 node added thanks to our (now 10-year sponsor), IONOS.
Uploaded the devscripts package, incorporating changes from Jochen Sprickerhof to the debrebuild script specifically to fix the handling the Rules-Requires-Root header in Debian source packages.
Uploaded a number of Rust dependencies of rebuilderd (rust-libbz2-rs-sys, rust-actix-web, rust-actix-server, rust-actix-http, rust-actix-server, rust-actix-http, rust-actix-web-codegen and rust-time-tz) after they were prepared by kpcyrd :
Jochen Sprickerhof also updated the sbuild package to:
Obey requests from the user/developer for a different temporary directory.
Use the root/superuser for some values of Rules-Requires-Root.
Don t pass --root-owner-group to old versions of dpkg.
Upstream patches
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:
go (clear GOROOT for func ldShared when -trimpath is used)
Distribution work
There as been the usual work in various distributions this month, such as:
In Debian, 17 reviews of Debian packages were added, 6 were updated and 8 were removed this month adding to our knowledge about identified issues.
Fedora developers Davide Cavalca and Zbigniew J drzejewski-Szmek gave a talk on Reproducible Builds in Fedora (PDF), touching on SRPM-specific issues as well as the current status and future plans.
Thanks to an investment from the Sovereign Tech Agency, the FreeBSD project s work on unprivileged and reproducible builds continued this month. Notable fixes include:
The Yocto Project has been struggling to upgrade to the latest Go and Rust 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.
Yocto continues to maintain its ability to binary reproduce all of the recipes in OpenEmbedded-Core, regardless of the build host distribution or the current build path.
Finally, Douglas DeMaio published an article on the openSUSE blog on announcing that the Reproducible-openSUSE (RBOS) Project Hits [Significant] Milestone. In particular:
The Reproducible-openSUSE (RBOS) 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.
diffoscope & strip-nondeterminismdiffoscope 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 288 and 289 to Debian:
Add asar to DIFFOSCOPE_FAIL_TESTS_ON_MISSING_TOOLS in order to address Debian bug #1095057) []
Catch a CalledProcessError when calling html2text. []
Additionally, Vagrant Cascadian updated diffoscope in GNU Guix to version 287 [][] and 288 [][] as well as submitted a patch to update to 289 []. Vagrant also fixed an issue that was breaking reprotest on Guix [][].
strip-nondeterminism is our sister tool to remove specific non-deterministic results from a completed build. This month version 1.14.1-2 was uploaded to Debian unstable by Holger Levsen.
Website updates
There were a large number of improvements made to our website this month, including:
Holger Levsen clarified the name of a link to our old Wiki pages on the History page [] and added a number of new links to the Talks & Resources page [][].
James Addison update the website s own README file to document a couple of additional dependencies [][], as well as did more work on a future Getting Started guide page [][].
Reproducibility testing framework
The Reproducible Builds project operates a comprehensive testing framework running primarily at tests.reproducible-builds.org in order to check packages and other artifacts for reproducibility. In January, a number of changes were made by Holger Levsen, including:
Fix /etc/cron.d and /etc/logrotate.d permissions for Jenkins nodes. []
Add support for riscv64 architecture nodes. [][]
Grant Jochen Sprickerhof access to the o4 node. []
Disable the janitor-setup-worker. [][]
In addition:
kpcyrd fixed the /all/api/ API endpoints on reproduce.debian.net by altering the nginx configuration. []
James Addison updated reproduce.debian.net to display the so-called bad reasons hyperlink inline [] and merged the Categorized issues links into the Reproduced builds column [].
Jochen Sprickerhof also made some reproduce.debian.net-related changes, adding support for detecting a bug in the mmdebstrap package [] as well as updating some documentation [].
Roland Clobus continued their work on reproducible live images for Debian, making changes related to new clustering of jobs in openQA. []
And finally, both Holger Levsen [][][] and Vagrant Cascadian performed significant node maintenance. [][][][][]
If you are interested in contributing to the Reproducible Builds project, please visit our Contribute page on our website. However, you can get in touch with us via:
Another short status update of what happened on my side last
month. One larger blocks are the Phosh 0.45 release, also reviews
took a considerable amount of time. From the fun side debugging bananui and coming up with a fix in
phoc as well as setting up a small GSM network using osmocom to test more Cell Broadcast thingies were likely the most fun parts.
phosh
I have been testing fish for a couple months now (this file started on
2025-01-03T23:52:15-0500 according to stat(1)), and those are my
notes. I suspect people will have Opinions about my comments here. Do
not comment unless you have some Constructive feedback to provide: I
don't want to know if you think I am holding it Wrong. Consider that I
might have used UNIX shells for longer that you have lived.
I'm not sure I'll keep using fish, but so far it's the first shell
that survived heavy use outside of zsh(1) (unless you count
tcsh(1), but that was in another millenia).
My normal shell is bash(1), and it's still the shell I used
everywhere else than my laptop, as I haven't switched on all the
servers I managed, although it is available since August 2022 on
torproject.org servers. I first got interested in fish because they
ported to Rust, making it one of the rare shells out there
written in a "safe" and modern programming language, released after an
impressive ~2 year of work with Fish 4.0.
Cool things
Current directory gets shortened,
~/wikis/anarc.at/software/desktop/wayland shows up as
~/w/a/s/d/wayland
Autocompletion rocks.
Default prompt rocks. Doesn't seem vulnerable to command injection
assaults, at least it doesn't trip on the git-landmine.
It even includes pipe status output, which was a huge pain to
implement in bash. Made me realized that if the last command succeeds,
we don't see other failures, which is the case of my current prompt
anyways! Signal reporting is better than my bash implementation too.
So far the only modification I have made to the prompt is to add a
printf '\a' to output a bell.
By default, fish keeps a directory history (but separate from the
pushd stack), that can be navigated with cdh, prevd, and
nextd, dirh shows the history.
Less cool
I feel there's visible latency in the prompt creation.
POSIX-style functions (foo() true ) are unsupported. Instead,
fish uses whitespace-sensitive definitions like this:
function foo
true
end
This means my (modest) collection of POSIX functions need to be ported
to fish. Workaround: simple functions can be turned into aliases,
which fish supports (but implements using functions).
EOF heredocs are considered to be "minor syntactic sugar". I find
them frigging useful.
Process substitution is split on newlines, not whitespace. you need to
pipe through string split -n " " to get the equivalent.
<(cmd) doesn't exist: they claim you can use cmd foo - as a
replacement, but that's not correct: I used <(cmd) mostly where
foo does not support - as a magic character to say 'read from
stdin'.
Documentation is... limited. It seems mostly geared the web docs
which are... okay (but I couldn't find out about
~/.config/fish/conf.d there!), but this is really inconvenient when
you're trying to browse the manual pages. For example, fish thinks
there's a fish_prompt manual page, according to its own completion
mechanism, but man(1) cannot find that manual page. I can't find the
manual for the time command (which is actually a keyword!)
Fish renders multi-line commands with newlines. So if your terminal
looks like this, say:
Note that this is an issue specific to foot(1), alacritty(1) and
gnome-terminal(1) don't suffer from that issue. I have already filed
it upstream in foot and it is apparently fixed already.
Globbing is driving me nuts. You can't pass a * to a command
unless fish agrees it's going to match something. You need to escape
it if it doesn't immediately match, and then you need the called
command to actually support globbing. 202[345] doesn't match
folders named 2023, 2024, 2025, it will send the string
202[345] to the command.
Blockers
() is like $(): it's process substitution, and not a
subshell. This is really impractical: I use ( cd foo ; do_something)
all the time to avoid losing the current directory... I guess I'm
supposed to use pushd for this, but ouch. This wouldn't be so bad if
it was just for cd though. Clean constructs like this:
... which fails and suggests using begin/end, at which point: why
not just support the curly braces?
FOO=bar is not allowed. It's actually recognized syntax, but creates
a warning. We're supposed to use set foo bar instead. This really
feels like a needless divergence from standard.
Aliases are... peculiar. Typical constructs like alias mv="\mv -i"
don't work because fish treats aliases as a function definition, and
\ is not magical there. This can be worked around by specifying the
full path to the command, with e.g. alias mv="/bin/mv -i". Another
problem is trying to override a built-in, which seems completely
impossible. In my case, I like the time(1) command the way it
is, thank you very much, and fish provides no way to bypass that
builtin. It is possible to call time(1) with command time, but
it's not possible to replace the command keyword so that means a lot
of typing.
Again: you can't use \ to bypass aliases. This is a huge annoyance
for me. I would need to learn to type command in long form, and I
use that stuff pretty regularly. I guess I could alias command to
c or something, but this is one of those huge muscle memory challenges.
alt . doesn't always work the way i expect.
A Little Vice is a stand-alone self-published
magical girl novel. It
is the author's first novel.
C is a high school student and frequent near-victim of monster attacks.
Due to the nefarious work of Avaritia Wolf and her allies, his high school
is constantly attacked by Beasts, who are magical corruptions of some
internal desire taken to absurd extremes. Standing in their way are the
Angelic Saints: magical girls who transform into Saint Castitas, Saint
Diligentia, and Saint Temperantia and fight the monsters. The monsters for
some reason seem disposed to pick C as their victim for hostage-taking,
mind control, use as a human shield, and other rather traumatic
activities. He's always rescued by the Saints before any great harm is
done, but in some ways this makes the situation worse.
It is obvious to C that the Saints are his three friends Inessa, Ida, and
Temperance, even though no one else seems able to figure this out despite
the blatant clues. Inessa has been his best friend since childhood when
she was awkward and needed his support. Now, she and his other friends
have become literal heroes, beautiful and powerful and capable, constantly
protecting the school and innocent people, and C is little more than a
helpless burden to be rescued. More than anything else, he wishes he could
be an Angelic Saint like them, but of course the whole idea is impossible.
Boys don't get to be magical girls.
(I'm using he/him pronouns for C in this review because C uses them for
himself for most of the book.)
This is a difficult book to review because it is deeply focused on
portraying a specific internal emotional battle in all of its
sometimes-ugly complexity, and to some extent it prioritizes that
portrayal over conventional story-telling. You have probably already
guessed that this is a transgender coming-out story Elkin's choice of
the magical girl genre was done with deep understanding of its role in
transgender narratives but more than that, it is a transgender
coming-out story of a very specific and closely-observed type. C knows who
he wishes he was, but he is certain that this transformation is absolutely
impossible. He is very deep in a cycle of self-loathing for wanting
something so manifestly absurd and insulting to people who have the
virtues that C does not.
A Little Vice is told in the first person from C's perspective, and
most of this book is a relentless observation of C's anxiety and shame
spiral and reflexive deflection of any possibility of a way out. This is
very well-written: Elkin knows the reader is going to disagree with C's
internalized disgust and hopelessness, knows the reader desperately wants
C to break out of that mindset, and clearly signals in a myriad of adroit
ways that Elkin is on the reader's side and does not agree with C's
analysis. C's friends are sympathetic, good-hearted people, and while
sometimes oblivious, it is obvious to the reader that they're also on the
reader's side and would help C in a heartbeat if they saw an opening. But
much of the point of the book is that it's not that easy, that breaking
out of the internal anxiety spiral is nearly impossible, and that C is
very good at rejecting help, both because he cannot imagine what form it
could take but also because he is certain that he does not deserve it.
In other words, much of the reading experience of this book involves
watching C torture and insult himself. It's all the more effective because
it isn't gratuitous. C's internal monologue sounds exactly like how an
anxiety spiral feels, complete with the sort of half-effective coping
mechanisms, deflections, and emotional suppression one develops to blunt
that type of emotional turmoil.
I normally hate this kind of book. I am a happy ending and competence porn
reader by default. The world is full of enough pain that I don't turn to
fiction to read about more pain. It says a lot about how well-constructed
this book is that I stuck with it. Elkin is going somewhere with the
story, C gets moments of joy and delight along the way to keep the reader
from bogging down completely, and the best parts of the book feel like a
prolonged musical crescendo with suspended chords. There is a
climax coming, but Elkin is going to make you wait for it for far longer
than you want to.
The main element that protects A Little Vice from being too grim is
that it is a genre novel that is very playful about both magical girls and
superhero tropes in general. I've already alluded to one of those
elements: Elkin plays with the Mask Principle (the inability of people to
see through entirely obvious secret identities) in knowing and
entertaining ways. But there are also villains, and that leads me to the
absolutely delightful Avaritia Wolf, who for me was the best character in
this book.
The Angelic Saints are not the only possible approach to magical girl
powers in this universe. There are villains who can perform a similar
transformation, except they embrace a vice rather than a virtue. Avaritia
Wolf embraces the vice of greed. They (Avaritia's pronouns change over the
course of the book) also have a secret identity, which I suspect will be
blindingly obvious to most readers but which I'll avoid mentioning since
it's still arguably a spoiler.
The primary plot arc of this book is an attempt to recruit C to the side
of the villains. The Beasts are drawn to him because he has magical
potential, and the villains are less picky about gender. This initially
involves some creepy and disturbing mind control, but it also brings C
into contact with Avaritia and Avaritia's very specific understanding of
greed. As far as Avaritia is concerned, greed means wanting whatever they
want, for whatever reason they feel like wanting it, and there is
absolutely no reason why that shouldn't include being greedy for their
friends to be happy. Or doing whatever they can to make their friends
happy, whether or not that looks like villainy.
Elkin does two things with this plot that I thought were remarkably
skillful. The first is that she directly examines and then undermines the
"easy" transgender magical girl ending. In a world of transformation
magic, someone who wants to be a girl could simply turn into a girl and
thus apparently resolve the conflict in a way that makes everyone happy. I
think there is an important place for that story (I am a vigorous defender
of escapist fantasy and happy endings), but that is not the story that
Elkin is telling. I won't go into the details of why and how the story
complicates and undermines this easy ending, but it's a lot of why this
book feels both painful and honest to a specific, and very not easy,
transgender experience, even though it takes place in an utterly
unrealistic world.
But the second, which is more happy and joyful, is that Avaritia gleefully
uses a wholehearted embrace of every implication of the vice of greed to
bulldoze the binary morality of the story and question the classification
of human emotions into virtues and vices. They are not a hero, or even all
that good; they have some serious flaws and a very anarchic attitude
towards society. But Avaritia provides the compelling, infectious thrill
of the character who looks at the social construction of morality that is
constraining the story and decides that it's all bullshit and refuses to
comply. This is almost the exact opposite of C's default emotional
position at the start of the book, and watching the two characters play
off of each other in a complex friendship is an absolute delight.
The ending of this book is complicated, messy, and incomplete. It is the
sort of ending that I think could be incredibly powerful if it hits
precisely the right chords with the reader, but if you're not that reader,
it can also be a little heartbreaking because Elkin refuses to provide an
easy resolution. The ending also drops some threads that I wish Elkin
hadn't dropped; there are some characters who I thought deserved a
resolution that they don't get. But this is one of those books where the
author knows exactly what story they're trying to tell and tells it
whether or not that fits what the reader wants. Those books are often not
easy reading, but I think there's something special about them.
This is not the novel for people who want detailed world-building that
puts a solid explanation under events. I thought Elkin did a great job
playing with the conventions of an episodic anime, including starting the
book on Episode 12 to imply C's backstory with monster attacks and hinting
at a parallel light anime story by providing TV-trailer-style plot
summaries and teasers at the start and end of each chapter. There is a
fascinating interplay between the story in which the Angelic Saints are
the protagonists, which the reader can partly extrapolate, and the novel
about C that one is actually reading. But the details of the
world-building are kept at the anime plot level: There's an arch-villain,
a World Tree, and a bit of backstory, but none of it makes that much sense
or turns into a coherent set of rules. This is a psychological novel; the
background and rules exist to support C's story.
If you do want that psychological novel... well, I'm not sure whether to
recommend this book or not. I admire the construction of this book a great
deal, but I don't think appealing to the broadest possible audience was
the goal. C's anxiety spiral is very repetitive, because anxiety spirals
are very repetitive, and you have to be willing to read for the grace
notes on the doom loop if you're going to enjoy this book. The
sentence-by-sentence writing quality is fine but nothing remarkable, and
is a bit shy of the average traditionally-published novel. The main appeal
of A Little Vice is in the deep and unflinching portrayal of a
specific emotional journey. I think this book is going to work if you're
sufficiently invested in that journey that you are willing to read the
brutal and repetitive parts. If you're not, there's a chance you will
bounce off this hard.
I was invested, and I'm glad I read this, but caveat emptor. You
may want to try a sample first.
One final note: If you're deep in the book world, you may wonder, like I
did, if the title is a reference to Hanya Yanagihara's (in)famous A
Little Life. I do not know for certain I have not read that book
because I am not interested in being emotionally brutalized but if it
is, I don't think there is much similarity. Both books are to some extent
about four friends, but I couldn't find any other obvious connections from
some Wikipedia reading, and A Little Vice, despite C's emotional
turmoil, seems to be considerably more upbeat.
Content notes: Emotionally abusive parent, some thoughts of self-harm,
mind control, body dysmorphia, and a lot (a lot) of shame and
self-loathing.
Rating: 7 out of 10
Introduction
This is just a note-taking about how to upgrading Mozc package for up-coming trixie ready (with many restrictions) last year.
Maybe Mozc 2.29.5160.102+dfsg-1.3 will be shipped for Debian 13 (trixie).
FTBFS with Mozc 2.28.4715.102+dfsg-2.2
In May 2024, I've found that Mozc was removed from testing, and still in FTBFS.
#1068186 - mozc: FTBFS with abseil 20230802: ../../base/init_mozc.cc:90:29: error: absl::debian5::flags_internal::ArgvListAction has not been declared - Debian Bug report logs
That FTBFS was fixed in the Mozc upstream, but not applied for a while.
Not only upstream patch, but also additional linkage patch was required to fix it.
Mozc is the de-fact standard input method editor for Japanese.
Most of Japanese uses it by default on linux desktop.
(Even though frontend input method framework is different, the background engine is Mozc in most cases -
uim-mozc for task-japanese-desktop, ibus-mozc for task-japanese-gnome-desktop in Debian)
There is a case that Mozc was re-built locally with integrated external dictionary
to improve quantity of vocabulary. If FTBFS keep ongoing, it means that it blocks such a usage.
So I've sent patches to fix it and they were merged.
Motivation to update Mozc
With fixing #1068186, I've also found Mozc version is not synced to upstream for a long time.
At that time, Mozc in unstable was version 2.28.4715.102+dfsg, but upstream already released 2.30.5544.102.
It seems that Mozc's maintainer was too busy and can't afford to update it, so I've tried to do it.
The blockers for updating Mozc
But, it was not so easy task to do so.
If you want to package latest Mozc, there were many blockers.
Newer Mozc requires Bazel to build, but there is no Bazel package to fit it (There is bazel-bootstrap 4.x, but it's old. v6.x or newer one is required.)
Newer abseil and protobuf were required
Renderer was changed to Qt. GTK renderer was removed
Revise existing patchsets (e.g. for UIM, for Fcitx)
It was not all.
Road to latest Mozc
First, I knew the existence of debian-bazel, so I've posted about bazel-packaging progress.
Any updates about bazel packaging effort?
Sadly there was no response from it.
Thus, it was not realistic to adopt Bazel as build tool chain.
In other words, we need to keep GYP patch and maintain it.
And as another topic, upstream changed renderer from GTK+ to Qt.
Here are the major topics about each release of Mozc.
The internal renderer change are too big, and before GYP deprecation
in 2.29.5544.102, GYP support was already removed gradually.
As a result, target to 2.29.5160.102 was the practical approach to make it forward.
Revisit existing patchsets for 2.28.4715.102+dfsg
Second, need to revisit existing patchset to triage them.
UIM patch was maintained in third-party repository,
and directory structure was quite different from Mozc.
It seems that maintenance activity was too low, so it was not enough that picking changes
from macuim. It was required to fix FTBFS additionally.
Fcitx patch was also maintained in fcitx/mozc.
But it tracks only master branch, so it was hard to pick patchset for specific version of Mozc.
Finally, I could manage to refresh patchset for 2.29.5160.102.
OT: Hardware breakage
There was another blocker to do this task.
I've hit the situation that g++ cause SEGV during building Mozc randomly.
First, I wonder why it fails, but digging further more, finally I've found that
memory module was corrupted. Thus I've lost 32GB memory modules. :-<
Unexpected behaviour in uim-mozc
When uploaded Mozc 2.29.5160.102+dfsg-1 to experimental,
I've found that there is a case that uim-mozc behaves weird.
The candidate words were shown with flickering.
But it was not regression in this upload.
uim-mozc with Wayland cause that problem.
Thus GNOME and derivatives might not be affected because ibus-mozc will be used.
Mozc 2.29.5160.102+dfsg-1
As the patchset was matured, then uploaded 2.29.5160.102+dfsg-1 with --delayed 15 option.
$ dput --delayed 15 mozc_2.29.5160.102+dfsg-1_source.changes
Uploading mozc using ftp to ftp-master (host: ftp.upload.debian.org; directory: /pub/UploadQueue/DELAYED/15-day)
running allowed-distribution: check whether a local profile permits uploads to the target distribution
running protected-distribution: warn before uploading to distributions where a special policy applies
running checksum: verify checksums before uploading
running suite-mismatch: check the target distribution for common errors
running gpg: check GnuPG signatures before the upload
signfile dsc mozc_2.29.5160.102+dfsg-1.dsc 719EB2D93DBE9C4D21FBA064F7FB75C566ED20E3
fixup_buildinfo mozc_2.29.5160.102+dfsg-1.dsc mozc_2.29.5160.102+dfsg-1_amd64.buildinfo
signfile buildinfo mozc_2.29.5160.102+dfsg-1_amd64.buildinfo 719EB2D93DBE9C4D21FBA064F7FB75C566ED20E3
fixup_changes dsc mozc_2.29.5160.102+dfsg-1.dsc mozc_2.29.5160.102+dfsg-1_source.changes
fixup_changes buildinfo mozc_2.29.5160.102+dfsg-1_amd64.buildinfo mozc_2.29.5160.102+dfsg-1_source.changes
signfile changes mozc_2.29.5160.102+dfsg-1_source.changes 719EB2D93DBE9C4D21FBA064F7FB75C566ED20E3
Successfully signed dsc, buildinfo, changes files
Uploading mozc_2.29.5160.102+dfsg-1.dsc
Uploading mozc_2.29.5160.102+dfsg-1.debian.tar.xz
Uploading mozc_2.29.5160.102+dfsg-1_amd64.buildinfo
Uploading mozc_2.29.5160.102+dfsg-1_source.changes
Mozc 2.29.5160.102+dfsg-1 was landed to unstable at 2024-12-20.
Additional bug fixes
Additionally, the following bugs were also fixed.
These bugs were fixed in 2.29.5160.102+dfsg-1.1
And more, I've found that even though missing pristine-tar branch commit, salsa CI succeeds.
I've sent MR for this issue and already merged into.
Note that protobuf 3.25.4 on experimental depends on older absl
20230802, so it must be rebuilt against absl 20240722.0.
And more, we need to consider how to migrate from GTK renderer to
Qt renderer in the future.
I can t remember exactly the joke I was making at the time in my
work s slack instance (I m sure it wasn t particularly
funny, though; and not even worth re-reading the thread to work out), but it
wound up with me writing a UEFI binary for the punchline. Not to spoil the
ending but it worked - no pesky kernel, no messing around with userland . I
guess the only part of this you really need to know for the setup here is that
it was a Severance joke,
which is some fantastic TV. If you haven t seen it, this post will seem perhaps
weirder than it actually is. I promise I haven t joined any new cults. For
those who have seen it, the payoff to my joke is that I wanted my machine to
boot directly to an image of
Kier Eagan.
As for how to do it I figured I d give the uefi
crate a shot, and see how it is to use,
since this is a low stakes way of trying it out. In general, this isn t the
sort of thing I d usually post about except this wound up being easier and
way cleaner than I thought it would be. That alone is worth sharing, in the
hopes someome comes across this in the future and feels like they, too, can
write something fun targeting the UEFI.
First thing s first gotta create a rust project (I ll leave that part to you
depending on your life choices), and to add the uefi crate to your
Cargo.toml. You can either use cargo add or add a line like this by hand:
uefi = version = "0.33", features = ["panic_handler", "alloc", "global_allocator"]
We also need to teach cargo about how to go about building for the UEFI target,
so we need to create a rust-toolchain.toml with one (or both) of the UEFI
targets we re interested in:
Unfortunately, I wasn t able to use the
image crate,
since it won t build against the uefi target. This looks like it s
because rustc had no way to compile the required floating point operations
within the image crate without hardware floating point instructions
specifically. Rust tends to punt a lot of that to libm usually, so this isnt
entirely shocking given we re nostd for a non-hardfloat target.
So-called softening requires a software floating point implementation that
the compiler can use to polyfill (feels weird to use the term polyfill here,
but I guess it s spiritually right?) the lack of hardware floating point
operations, which rust hasn t implemented for this target yet. As a result, I
changed tactics, and figured I d use ImageMagick to pre-compute the pixels
from a jpg, rather than doing it at runtime. A bit of a bummer, since I need
to do more out of band pre-processing and hardcoding, and updating the image
kinda sucks as a result but it s entirely manageable.
This will take our input file (kier.jpg), resize it to get as close to the
desired resolution as possible while maintaining aspect ration, then convert it
from a jpg to a flat array of 4 byte RGBA pixels. Critically, it s also
important to remember that the size of the kier.full.jpg file may not actually
be the requested size it will not change the aspect ratio, so be sure to
make a careful note of the resulting size of the kier.full.jpg file.
Last step with the image is to compile it into our Rust bianary, since we
don t want to struggle with trying to read this off disk, which is thankfully
real easy to do.
Remember to use the width and height from the final kier.full.jpg file as the
values for KIER_WIDTH and KIER_HEIGHT. KIER_PIXEL_SIZE is 4, since we
have 4 byte wide values for each pixel as a result of our conversion step into
RGBA. We ll only use RGB, and if we ever drop the alpha channel, we can drop
that down to 3. I don t entirely know why I kept alpha around, but I figured it
was fine. My kier.full.jpg image winds up shorter than the requested height
(which is also qemu s default resolution for me) which means we ll get a
semi-annoying black band under the image when we go to run it but it ll
work.
Anyway, now that we have our image as bytes, we can get down to work, and
write the rest of the code to handle moving bytes around from in-memory
as a flat block if pixels, and request that they be displayed using the
UEFI GOP. We ll just need to hack up a container
for the image pixels and teach it how to blit to the display.
/// RGB Image to move around. This isn't the same as an
/// image::RgbImage , but we can associate the size of
/// the image along with the flat buffer of pixels.
structRgbImage/// Size of the image as a tuple, as the
/// (width, height)
size: (usize, usize),
/// raw pixels we'll send to the display.
inner: Vec<BltPixel>,
impl RgbImage
/// Create a new RgbImage .
fnnew(width: usize, height: usize) -> Self
RgbImage
size: (width, height),
inner: vec![BltPixel::new(0, 0, 0); width * height],
/// Take our pixels and request that the UEFI GOP
/// display them for us.
fnwrite(&self, gop: &mut GraphicsOutput) -> Result
gop.blt(BltOp::BufferToVideo
buffer: &self.inner,
src: BltRegion::Full,
dest: (0, 0),
dims: self.size,
)
impl Index<(usize, usize)>for RgbImage
typeOutput= BltPixel;
fnindex(&self, idx: (usize, usize)) -> &BltPixellet (x, y) = idx;
&self.inner[y * self.size.0+ x]
impl IndexMut<(usize, usize)>for RgbImage
fnindex_mut(&mut self, idx: (usize, usize)) -> &mut BltPixel
let (x, y) = idx;
&mut self.inner[y * self.size.0+ x]
We also need to do some basic setup to get a handle to the UEFI
GOP via the UEFI crate (using
uefi::boot::get_handle_for_protocol
and
uefi::boot::open_protocol_exclusive
for the GraphicsOutput
protocol), so that we have the object we need to pass to RgbImage in order
for it to write the pixels to the display. The only trick here is that the
display on the booted system can really be any resolution so we need to do
some capping to ensure that we don t write more pixels than the display can
handle. Writing fewer than the display s maximum seems fine, though.
fnpraise() -> Result
let gop_handle = boot::get_handle_for_protocol::<GraphicsOutput>()?;
letmut gop = boot::open_protocol_exclusive::<GraphicsOutput>(gop_handle)?;
// Get the (width, height) that is the minimum of
// our image and the display we're using.
let (width, height) = gop.current_mode_info().resolution();
let (width, height) = (width.min(KIER_WIDTH), height.min(KIER_HEIGHT));
letmut buffer = RgbImage::new(width, height);
for y in0..height
for x in0..width
let idx_r = ((y * KIER_WIDTH) + x) * KIER_PIXEL_SIZE;
let pixel =&mut buffer[(x, y)];
pixel.red = KIER[idx_r];
pixel.green = KIER[idx_r +1];
pixel.blue = KIER[idx_r +2];
buffer.write(&mut gop)?;
Ok(())
Not so bad! A bit tedious we could solve some of this by turning
KIER into an RgbImage at compile-time using some clever Cow and
const tricks and implement blitting a sub-image of the image but this
will do for now. This is a joke, after all, let s not go nuts. All that s
left with our code is for us to write our main function and try and boot
the thing!
#[entry]fnmain() -> Status
uefi::helpers::init().unwrap();
praise().unwrap();
boot::stall(100_000_000);
Status::SUCCESS
If you re following along at home and so interested, the final source is over at
gist.github.com.
We can go ahead and build it using cargo (as is our tradition) by targeting
the UEFI platform.
Testing the UEFI Blob
While I can definitely get my machine to boot these blobs to test, I figured
I d save myself some time by using QEMU to test without a full boot.
If you ve not done this sort of thing before, we ll need two packages,
qemu and ovmf. It s a bit different than most invocations of qemu you
may see out there so I figured it d be worth writing this down, too.
$ doas apt install qemu-system-x86 ovmf
qemu has a nice feature where it ll create us an EFI partition as a drive and
attach it to the VM off a local directory so let s construct an EFI
partition file structure, and drop our binary into the conventional location.
If you haven t done this before, and are only interested in running this in a
VM, don t worry too much about it, a lot of it is convention and this layout
should work for you.
With all this in place, we can kick off qemu, booting it in UEFI mode using
the ovmf firmware, attaching our EFI partition directory as a drive to
our VM to boot off of.
If all goes well, soon you ll be met with the all knowing gaze of
Chosen One, Kier Eagan. The thing that really impressed me about all
this is this program worked first try it all went so boringly
normal. Truly, kudos to the uefi crate maintainers, it s incredibly
well done.
Booting a live system
Sure, we could stop here, but anyone can open up an app window and see a
picture of Kier Eagan, so I knew I needed to finish the job and boot a real
machine up with this. In order to do that, we need to format a USB stick.
BE SURE /dev/sda IS CORRECT IF YOU RE COPY AND PASTING. All my drives
are NVMe, so BE CAREFUL if you use SATA, it may very well be your
hard drive! Please do not destroy your computer over this.
$ doas fdisk /dev/sda
Welcome to fdisk (util-linux 2.40.4).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-4014079, default 2048):
Last sector, +/-sectors or +/-size K,M,G,T,P (2048-4014079, default 4014079):
Created a new partition 1 of type 'Linux' and of size 1.9 GiB.
Command (m for help): t
Selected partition 1
Hex code or alias (type L to list all): ef
Changed type of partition 'Linux' to 'EFI (FAT-12/16/32)'.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Once that looks good (depending on your flavor of udev you may or
may not need to unplug and replug your USB stick), we can go ahead
and format our new EFI partition (BE CAREFUL THAT /dev/sda IS YOUR
USB STICK) and write our EFI directory to it.
$ doas mkfs.fat /dev/sda1
$ doas mount /dev/sda1 /mnt
$ cp -r esp/efi /mnt
$ find /mnt
/mnt
/mnt/efi
/mnt/efi/boot
/mnt/efi/boot/bootx64.efi
Of course, naturally, devotion to Kier shouldn t mean backdooring your system.
Disabling Secure Boot runs counter to the Core Principals, such as Probity, and
not doing this would surely run counter to Verve, Wit and Vision. This bit does
require that you ve taken the step to enroll a
MOK and know how
to use it, right about now is when we can use sbsign to sign our UEFI binary
we want to boot from to continue enforcing Secure Boot. The details for how
this command should be run specifically is likely something you ll need to work
out depending on how you ve decided to manage your MOK.
I figured I d leave a signed copy of boot2kier at
/boot/efi/EFI/BOOT/KIER.efi on my Dell XPS 13, with Secure Boot enabled
and enforcing, just took a matter of going into my BIOS to add the right
boot option, which was no sweat. I m sure there is a way to do it using
efibootmgr, but I wasn t smart enough to do that quickly. I let er rip,
and it booted up and worked great!
It was a bit hard to get a video of my laptop, though but lucky for me, I
have a Minisforum Z83-F sitting around (which, until a few weeks ago was running
the annual http server to control my christmas tree
) so I grabbed it out of the christmas bin, wired it up to a video capture
card I have sitting around, and figured I d grab a video of me booting a
physical device off the boot2kier USB stick.
Attentive readers will notice the image of Kier is smaller then the qemu booted
system which just means our real machine has a larger GOP display
resolution than qemu, which makes sense! We could write some fancy resize code
(sounds annoying), center the image (can t be assed but should be the easy way
out here) or resize the original image (pretty hardware specific workaround).
Additionally, you can make out the image being written to the display before us
(the Minisforum logo) behind Kier, which is really cool stuff. If we were real
fancy we could write blank pixels to the display before blitting Kier, but,
again, I don t think I care to do that much work.
But now I must away
If I wanted to keep this joke going, I d likely try and find a copy of the
original
video when Helly 100%s her file
and boot into that or maybe play a terrible midi PC speaker rendition of
Kier, Chosen One, Kier after
rendering the image. I, unfortunately, don t have any friends involved with
production (yet?), so I reckon all that s out for now. I ll likely stop playing
with this the joke was done and I m only writing this post because of how
great everything was along the way.
All in all, this reminds me so much of building a homebrew kernel to boot a
system into but like, good, though, and it s a nice reminder of both how
fun this stuff can be, and how far we ve come. UEFI protocols are light-years
better than how we did it in the dark ages, and the tooling for this is SO
much more mature. Booting a custom UEFI binary is miles ahead of trying to
boot your own kernel, and I can t believe how good the uefi crate is
specifically.
Praise Kier! Kudos, to everyone involved in making this so delightful .
Well, 2024 will be remembered, won't it? I guess 2025 already wants to
make its mark too, but let's not worry about that right now, and
instead let's talk about me.
A little over a year ago, I was gloating
over how I had such a great blogging year in 2022, and was considering
2023 to be average, then went on to gather more stats and traffic
analysis... Then I said, and I quote:
I hope to write more next year. I've been thinking about a few posts I
could write for work, about how things work behind the scenes at Tor,
that could be informative for many people. We run a rather old setup,
but things hold up pretty well for what we throw at it, and it's worth
sharing that with the world...
What a load of bollocks.
A bad year for this blog
2024 was the second worst year ever in my blogging history, tied with
2009 at a measly 6 posts for the year:
Loads of drafts
It's not that I have nothing to say: I have no less than five drafts
in my working tree here, not counting three actual drafts recorded
in the Git repository here:
I just don't have time to wrap those things up. I think part of me is
disgusted by seeing my work stolen by large corporations to build
proprietary large language models while my idols have been pushed
to suicide for trying to share science with the world.
Another part of me wants to make those things just right. The
"tagged drafts" above are nothing more than a huge pile of chaotic
links, far from being useful for anyone else than me, and even
then.
The on-dying article, in particular, is becoming my nemesis. I've
been wanting to write that article for over 6 years now, I think. It's
just too hard.
Writing elsewhere
There's also the fact that I write for work already. A lot. Here are
the top-10 contributors to our team's wiki:
anarcat@angela:help.torproject.org$ git shortlog --numbered --summary --group="format:%al" head -10
4272 anarcat
423 jerome
117 zen
116 lelutin
104 peter
58 kez
45 irl
43 hiro
18 gaba
17 groente
... but that's a bit unfair, since I've been there half a
decade. Here's the last year:
anarcat@angela:help.torproject.org$ git shortlog --since=2024-01-01 --numbered --summary --group="format:%al" head -10
827 anarcat
117 zen
116 lelutin
91 jerome
17 groente
10 gaba
8 micah
7 kez
5 jnewsome
4 stephen.swift
So I still write the most commits! But to truly get a sense of the
amount I wrote in there, we should count actual changes. Here it is by
number of lines (from commandlinefu.com):
anarcat@angela:help.torproject.org$ git ls-files xargs -n1 git blame --line-porcelain sed -n 's/^author //p' sort -f uniq -ic sort -nr head -10
99046 Antoine Beaupr
6900 Zen Fu
4784 J r me Charaoui
1446 Gabriel Filion
1146 Jerome Charaoui
837 groente
705 kez
569 Gaba
381 Matt Traudt
237 Stephen Swift
That, of course, is the entire history of the git repo, again. We
should take only the last year into account, and probably ignore the
tails directory, as sneaky Zen Fu imported the entire docs from
another wiki there...
anarcat@angela:help.torproject.org$ find [d-s]* -type f -mtime -365 xargs -n1 git blame --line-porcelain 2>/dev/null sed -n 's/^author //p' sort -f uniq -ic sort -nr head -10
75037 Antoine Beaupr
2932 J r me Charaoui
1442 Gabriel Filion
1400 Zen Fu
929 Jerome Charaoui
837 groente
702 kez
569 Gaba
381 Matt Traudt
237 Stephen Swift
Pretty good! 75k lines. But those are the files that were modified in
the last year. If we go a little more nuts, we find that:
I wrote 126,116 words in that wiki, only in the last year. I also
deleted 37k words, so the final total is more like 89k words, but
still: that's about forty (40!) articles of the average size (~2k) I
wrote in 2022.
(And yes, I did go nuts and write a new log parser, essentially from
scratch, to figure out those word diffs. I did get the courage only
after asking GPT-4o for an example first, I must admit.)
Let's celebrate that again: I wrote 90 thousand words in that wiki
in 2024. According to Wikipedia, a "novella" is 17,500 to 40,000
words, which would mean I wrote about a novella and a novel, in the
past year.
But interestingly, if I look at the repository analytics. I
certainly didn't write that much more in the past year. So that
alone cannot explain the lull in my production here.
Arguments
Another part of me is just tired of the bickering and arguing on the
internet. I have at least two articles in there that I suspect is
going to get me a lot of push-back (NixOS and Fish). I know how to
deal with this: you need to write well, consider the controversy,
spell it out, and defuse things before they happen. But that's hard
work and, frankly, I don't really care that much about what people
think anymore.
I'm not writing here to convince people. I have stop evangelizing a
long time ago. Now, I'm more into documenting, and teaching. And,
while teaching, there's a two-way interaction: when you give out a
speech or workshop, people can ask questions, or respond, and you all
learn something. When you document, you quickly get told "where is
this? I couldn't find it" or "I don't understand this" or "I tried
that and it didn't work" or "wait, really? shouldn't we do X instead",
and you learn.
Here, it's static. It's my little soapbox where I scream in the
void. The only thing people can do is scream back.
Collaboration
So.
Let's see if we can work together here.
If you don't like something I say, disagree, or find something wrong
or to be improved, instead of screaming on social media or ignoring
me, try contributing back. This site here is backed by a git
repository and I promise to read everything you send there,
whether it is an issue or a merge request.
I will, of course, still read comments sent by email or IRC or social
media, but please, be kind.
You can also, of course, follow the latest changes on the TPA
wiki. If you want to catch up with the last year, some of the
"novellas" I wrote include:
TPA-RFC-71: Emergency email deployments, phase B: deploy a new
sender-rewriting mail forwarder, migrate mailing lists off the
legacy server to a new machine, migrate the remaining Schleuder list
to the Tails server, upgrade eugeni.
Another short status update of what happened on my side last
month. Mostly focused on quality of life improvements in phosh and
cleaning up and improving phoc this time around (including catching up
with wlroots git) but some improvements for other things like
phosh-osk-stub happened on the side line too.
phosh
Fix crash when switching bitween some fractional scales (MR)
Make layer surface code more flexible and fade in system modal dialogs (MR)
Allow events to override the sound feedback with custom sounds
(MR). Allows
desktop/mobile shells like phosh to honour application prefs for notifications.
udev regression affecting gmobile (Bug). Many thanks to Yu Watanabe
for providing the fix so quickly
Reviews
This is not code by me but reviews on other peoples code. The list is
incomplete, but I hope to improve on this in the upcoming
months. Thanks for the contributions!
Despite comments on my ikiwiki blog being fully moderated, spammers have
been increasingly posting link spam comments on my blog. While I used to use
the blogspam plugin, the
underlying service was likely retired circa
2017 and its public
repositories are all archived.
It turns out that there is a relatively simple way to drastically reduce the
amount of spam submitted to the moderation queue: ban the datacentre IP
addresses that spammers are using.
Looking up AS numbers
It all starts by looking at the IP address of a submitted comment:
From there, we can look it up using whois:
$ whois -r 2a0b:7140:1:1:5054:ff:fe66:85c5
% This is the RIPE Database query service.
% The objects are in RPSL format.
%
% The RIPE Database is subject to Terms and Conditions.
% See https://docs.db.ripe.net/terms-conditions.html
% Note: this output has been filtered.
% To receive output for a database update, use the "-B" flag.
% Information related to '2a0b:7140:1::/48'
% Abuse contact for '2a0b:7140:1::/48' is 'abuse@servinga.com'
inet6num: 2a0b:7140:1::/48
netname: EE-SERVINGA-2022083002
descr: servinga.com - Estonia
geoloc: 59.4424455 24.7442221
country: EE
org: ORG-SG262-RIPE
mnt-domains: HANNASKE-MNT
admin-c: CL8090-RIPE
tech-c: CL8090-RIPE
status: ASSIGNED
mnt-by: MNT-SERVINGA
created: 2020-02-18T11:12:49Z
last-modified: 2024-12-04T12:07:26Z
source: RIPE
% Information related to '2a0b:7140:1::/48AS207408'
route6: 2a0b:7140:1::/48
descr: servinga.com - Estonia
origin: AS207408
mnt-by: MNT-SERVINGA
created: 2020-02-18T11:18:11Z
last-modified: 2024-12-11T23:09:19Z
source: RIPE
% This query was served by the RIPE Database Query Service version 1.114 (SHETLAND)
Looking up IP blocks
Autonomous Systems are
essentially organizations to which
IPv4 and
IPv6 blocks have been allocated.
These allocations can be looked up easily on the command line either using a
third-party service:
Preventing comment submission
While I do want to eliminate this source of spam, I don't want to block
these datacentre IP addresses outright since legitimate users could be using
these servers as VPN endpoints or crawlers.
I therefore added the following to my Apache config to restrict the CGI
endpoint (used only for write operations such as commenting):
<Location /blog.cgi>
Include /etc/apache2/spammers.include
Options +ExecCGI
AddHandler cgi-script .cgi
</Location>
and then put the following in /etc/apache2/spammers.include:
<RequireAll>
Require all granted
# https://ipinfo.io/AS207408
Require not ip 46.11.183.0/24
Require not ip 80.77.25.0/24
Require not ip 194.76.227.0/24
Require not ip 2a0b:7140:1::/48
</RequireAll>
Finally, I can restart the website and commit my changes:
$ apache2ctl configtest && systemctl restart apache2.service
$ git commit -a -m "Ban all IP blocks from Servinga"
Future improvements
I will likely automate this process in the future, but at the moment my
blog can go for a week without a single spam message (down from dozens every
day). It's possible that I've already cut off the worst offenders.
I have published the list I am currently using.
I ve always been a fan of template engines that work with text files, mainly to work with static site generators, but
also to generate code, configuration files, and other text-based files.
For my own web projects I used to go with Jinja2, as all my projects were written
in Python, while for static web sites I used the template engines included with the tools I was
using, i.e. Liquid with Jekyll and
Go Templates (based on the text/template
and the html/template go packages) for Hugo.
When I needed to generate code snippets or configuration files from shell scripts I used to go with
sed and/or
envsubst, but lately things got complicated and I started to use
a command line application called tmpl that uses the Go
Template Language with functions from the Sprig library.
tmplI ve been using my fork of the tmpl program to process templates on CI/CD pipelines
(gitlab-ci) to generate configuration files and code snippets because it uses the same syntax used by
helm (easier to use by other DevOps already familiar with the format) and the binary is small and
can be easily included into the docker images used by the pipeline jobs.
One interesting feature of the tmpl tool is that it can read values from command line arguments and from multiple
files in different formats (YAML, JSON, TOML, etc) and merge them into a single object that can be used to render the
templates.
There are alternatives to the tmpl tool and I ve looked at them (i.e. simple ones like
go-template-cli or complex ones like
gomplate), but I haven t found one that fits my needs.
For my next project I plan to evaluate a move to a different tool or template format, as tmpl is not being actively
maintained (as I said, I m using my own fork) and it is not included on existing GNU/Linux distributions (I packaged it
for Debian and Alpine, but I don t want to maintain something like that without an active community and I m not
interested in being the upstream myself, as I m trying to move to Rust instead of
Go as the compiled programming language for my projects).
Mini JinjaLooking for alternate tools to process templates on the command line I found the minijinja
rust crate, a minimal implementation of the Jinja2 template engine that also includes a small command line utility
(minijinja-cli) and I believe I ll give it a try on the future for various
reasons:
I m already familiar with the Jinja2 syntax and it is widely used on the industry.
On my code I can use the original Jinja2 module for Python projects and MiniJinja for Rust programs.
The included command line utility is small and easy to use, and the binaries distributed by the project are good
enough to add them to the docker container images used by CI/CD pipelines.
As I want to move to Rust I can try to add functionalities to the existing command line client or create my own
version of it if they are needed (don t think so, but who knows).
On recent weeks I ve had some time to scratch my own itch on
matters related to tools I use daily on my computer, namely the desktop / window manager and my text editor of choice.
This post is a summary of what I tried, how it worked out and my short and medium-term plans related to them.
Desktop / WMOn the desktop / window manager front I ve been using Cinnamon on Debian
and Ubuntu systems since Gnome 3 was published (I never liked version 3, so I decided to move to something similar
to Gnome 2, including the keyboard shortcuts).
In fact I ve never been a fan of Desktop environments, before Gnome I used OpenBox and
IceWM because they where a lot faster than desktop systems on my hardware at the time and I was
using them only to place one or two windows on multiple workspaces using mainly the keyboard for my interactions (well,
except for the web browsers and the image manipulation programs).
Although I was comfortable using Cinnamon, some years ago I tried to move to i3, a tilling window
manager for X11 that looked like a good choice for me, but I didn t have much time to play with it and never used it
enough to make me productive with it (I didn t prepare a complete configuration nor had enough time to learn the new
shortcuts, so I went back to Cinnamon and never tried again).
Anyway, some weeks ago I updated my work machine OS (it was using Ubuntu 22.04 LTS and I updated it to the 24.04
LTS version) and the Cinnamon systray applet stopped working as it used to do (in fact I still have to restart
Cinnamon after starting a session to make it work) and, as I had some time, I decided to try a tilling window
manager again, but now I decided to go for SwayWM, as it uses
Wayland instead of X11.
Sway configurationOn my ~/.config/sway/config I tuned some things:
Installed manually the shikane application and created a configuration to be
executed always when sway is started / reloaded (I adjusted my configuration with wdisplays and used shikanectl
to save it).
Added support for running the
xdg-desktop-portal-wlr service.
Enabled the swayidle command to lock the screen after some time of inactivity.
Adjusted the keyboard to use the es key map
Added some keybindings to make my life easier, including the use of grimm and swappy to take screenshots
Configured waybar as the environment bar.
Added a shell script to start applications when sway is started (it uses swaymsg to execute background commands
and the i3toolwait script to wait for the
#!/bin/sh# VARIABLESCHROMIUM_LOCAL_STATE="$HOME/.config/google-chrome/Local State"I3_TOOLWAIT="$HOME/.config/sway/scripts/i3-toolwait"# Functions
chromium_profile_dir()
jq -r".profile.info_cache to_entries map( (.value.name): .key ) add .\"$1\" // \"\"""$CHROMIUM_LOCAL_STATE"# MAINIGZ_PROFILE_DIR="$(chromium_profile_dir "sergio.talens@intelygenz.com")"OURO_PROFILE_DIR="$(chromium_profile_dir "sergio.talens@nxr.global")"PERSONAL_PROFILE_DIR="$(chromium_profile_dir "stalens@gmail.com")"# Common programs
swaymsg "exec nextcloud --background"
swaymsg "exec nm-applet"# Run spotify on the first workspace (it is mapped to the laptop screen)
swaymsg -q"workspace 1"$ I3_TOOLWAIT"spotify"# Run tmux on the
swaymsg -q"workspace 2"$ I3_TOOLWAIT-- foot tmux a -dt sto
wp_num="3"if["$OURO_PROFILE_DIR"];then
swaymsg -q"workspace $wp_num"$ I3_TOOLWAIT-m ouro-browser -- google-chrome --profile-directory="$OURO_PROFILE_DIR"wp_num="$((wp_num+1))"fi
if["$IGZ_PROFILE_DIR"];then
swaymsg -q"workspace $wp_num"$ I3_TOOLWAIT-m igz-browser -- google-chrome --profile-directory="$IGZ_PROFILE_DIR"wp_num="$((wp_num+1))"fi
if["$PERSONAL_PROFILE_DIR"];then
swaymsg -q"workspace $wp_num"$ I3_TOOLWAIT-m personal-browser -- google-chrome --profile-directory="$PERSONAL_PROFILE_DIR"wp_num="$((wp_num+1))"fi# Open the browser without setting the profile directory if none was foundif["$wp_num"="3"];then
swaymsg -q"workspace $wp_num"$ I3_TOOLWAIT google-chrome
wp_num="$((wp_num+1))"fi
swaymsg -q"workspace $wp_num"$ I3_TOOLWAIT evolution
wp_num="$((wp_num+1))"
swaymsg -q"workspace $wp_num"$ I3_TOOLWAIT slack
wp_num="$((wp_num+1))"# Open a private browser and a console in the last workspace
swaymsg -q"workspace $wp_num"$ I3_TOOLWAIT-- google-chrome --incognito$ I3_TOOLWAIT foot
# Go back to the second workspace for keepassxc
swaymsg "workspace 2"$ I3_TOOLWAIT keepassxc
ConclusionAfter using Sway for some days I can confirm that it is a good choice for me, but some of the components needed to
make it work as I want are too new and not available on the Ubuntu 24.04 LTS repositories, so I decided to go back
to Cinnamon and try Sway again in the future, although I added more workspaces to my setup (now they are only
available on the main monitor, the laptop screen is fixed while there is a big monitor connected), added some
additional keyboard shortcuts and installed or updated some applets.
Text editorWhen I started using Linux many years ago I used vi/vim and emacs as my text editors (vi for plain text and
emacs for programming and editing HTML/XML), but eventually I moved to vim as my main text editor and I ve been
using it since (well, I moved to neovim some time ago, although I kept my old vim configuration).
To be fair I m not as expert as I could be with vim, but I m productive with it and it has many plugins that make my
life easier on my machines, while keeping my ability to edit text and configurations on any system that has a vi
compatible editor installed.
For work reasons I tried to use Visual Studio Code last year, but I ve never really
liked it and almost everything I do with it I can do with neovim (i. e. I even use copilot with it). Besides, I m a
heavy terminal user (I use tmux locally and via ssh) and I like to be able to use my text editor on my shell
sessions, and code does not work like that.
The only annoying thing about vim/neovim is its configuration (well, the problem is that I have a very old one and
probably should spend some time fixing and updating it), but, as I said, it s been working well for me for a long time,
so I never really had the motivation to do it.
Anyway, after finishing my desktop tests I saw that I had the Helix editor installed for
some time but I never tried it, so I decided to give it a try and see if it could be a good replacement for neovim on
my environments (the only drawback is that as it is not vi compatible, I would need to switch back to vi mode when
working on remote systems, but I guess I could live with that).
I ran the helix tutorial and I liked it, so I decided to configure and install the
Language Servers I can probably take
advantage of on my daily work on my personal and work machines and see how it works.
Language server installationsA lot of manual installations are needed to get the language servers working what I did on my machines is more or less
the following:
Helix configurationThe helix configuration is done on a couple of toml files that are placed on the ~/.config/helix directory,
the config.toml file I used is this one:
theme="solarized_light"[editor]line-number="relative"mouse=false[editor.statusline]left=["mode","spinner"]center=["file-name"]right=["diagnostics","selections","position","file-encoding","file-line-ending","file-type"]separator=" "mode.normal="NORMAL"mode.insert="INSERT"mode.select="SELECT"[editor.cursor-shape]insert="bar"normal="block"select="underline"[editor.file-picker]hidden=false[editor.whitespace]render="all"[editor.indent-guides]render=truecharacter=" "# Some characters that work well: " ", " ", " ", " "skip-levels=1
And to configure the language servers I used the following language-servers.toml file:
Neovim configurationAfter a little while I noticed that I was going to need some time to get used to helix and the most interesting thing
for me was the easy configuration and the language server integrations, but as I am already comfortable with neovim
and just had installed the language server support tools on my machines I just need to
configure them for neovim and I can keep using it for a while.
As I said my configuration is old, to configure neovim I have the following init.vim file on my ~/.config/nvim
folder:
setruntimepath^=~/.vim runtimepath+=~/.vim/after
let &packpath=&runtimepathsource~/.vim/vimrc
" load lua configurationlua require('config')
With that configuration I keep my old vimrc (it is a little bit messy, but it works) and I use a lua configuration
file for the language servers and some additional neovim plugins on the ~/.config/nvim/lua/config.lua file:
-- ------------------------- BEG: LSP Configurations-- ------------------------- AWS (awk_ls)require'lspconfig'.awk_ls.setup-- Bash (bashls)require'lspconfig'.bashls.setup-- C/C++ (clangd)require'lspconfig'.clangd.setup-- CSS (cssls)require'lspconfig'.cssls.setup-- Docker (dockerls)require'lspconfig'.dockerls.setup-- Docker Composerequire'lspconfig'.docker_compose_language_service.setup-- Golang (gopls)require'lspconfig'.gopls.setup-- Helm (helm_ls)require'lspconfig'.helm_ls.setup-- Markdownrequire'lspconfig'.marksman.setup-- Python (pyright)require'lspconfig'.pyright.setup-- Rust (rust-analyzer)require'lspconfig'.rust_analyzer.setup-- SQL (sqlls)require'lspconfig'.sqlls.setup-- Terraform (terraformls)require'lspconfig'.terraformls.setup-- TOML (taplo)require'lspconfig'.taplo.setup-- Typescript (ts_ls)require'lspconfig'.ts_ls.setup-- YAML (yamlls)require'lspconfig'.yamlls.setupsettings=yaml=customTags="!reference sequence"-- ------------------------- END: LSP Configurations-- ------------------------- ----------------------------------- BEG: Autocompletion configuration-- ----------------------------------- Ref: https://github.com/neovim/nvim-lspconfig/wiki/Autocompletion---- Pre requisites:---- # Packer-- git clone --depth 1 https://github.com/wbthomason/packer.nvim \-- ~/.local/share/nvim/site/pack/packer/start/packer.nvim---- # Start nvim and run :PackerSync or :PackerUpdate-- ---------------------------------localuse=require('packer').userequire('packer').startup(function()use'wbthomason/packer.nvim'-- Packer, useful to avoid removing it with PackerSync / PackerUpdateuse'neovim/nvim-lspconfig'-- Collection of configurations for built-in LSP clientuse'hrsh7th/nvim-cmp'-- Autocompletion pluginuse'hrsh7th/cmp-nvim-lsp'-- LSP source for nvim-cmpuse'saadparwaiz1/cmp_luasnip'-- Snippets source for nvim-cmpuse'L3MON4D3/LuaSnip'-- Snippets pluginend)-- Add additional capabilities supported by nvim-cmplocalcapabilities=require("cmp_nvim_lsp").default_capabilities()locallspconfig=require('lspconfig')-- Enable some language servers with the additional completion capabilities offered by nvim-cmplocalservers='clangd','rust_analyzer','pyright','ts_ls'for_,lspinipairs(servers)dolspconfig[lsp].setup-- on_attach = my_custom_on_attach,capabilities=capabilities,end-- luasnip setuplocalluasnip=require'luasnip'-- nvim-cmp setuplocalcmp=require'cmp'cmp.setupsnippet=expand=function(args)luasnip.lsp_expand(args.body)end, ,mapping=cmp.mapping.preset.insert( ['<C-u>']=cmp.mapping.scroll_docs(-4),-- Up['<C-d>']=cmp.mapping.scroll_docs(4),-- Down-- C-b (back) C-f (forward) for snippet placeholder navigation.['<C-Space>']=cmp.mapping.complete(),['<CR>']=cmp.mapping.confirmbehavior=cmp.ConfirmBehavior.Replace,select=true, ,['<Tab>']=cmp.mapping(function(fallback)ifcmp.visible()thencmp.select_next_item()elseifluasnip.expand_or_jumpable()thenluasnip.expand_or_jump()elsefallback()endend,'i','s' ),['<S-Tab>']=cmp.mapping(function(fallback)ifcmp.visible()thencmp.select_prev_item()elseifluasnip.jumpable(-1)thenluasnip.jump(-1)elsefallback()endend,'i','s' ), ),sources=name='nvim_lsp' ,name='luasnip' , ,-- ----------------------------------- END: Autocompletion configuration-- ---------------------------------
ConclusionI guess I ll keep helix installed and try it again on some of my personal projects to see if I can get used to it,
but for now I ll stay with neovim as my main text editor and learn the shortcuts to use it with the language servers.
To know about how Han-Unification is harmful for Japanese in some cases,
See "Your Code Displays Japanese Wrong".
heistak.github.io
When building d-i (GUI Installer), you need to build build_netboot-gtk target.
But note that you need recent master because it has nitpick issue with GNU Make 4.4.x.
bugs.debian.org
After that, need to prepare required packages. See README in details.
It seems that Bug#1037256 will be fixed with supporting compressed font.
I don't know how to do it furthermore ,
but I'm sure that Mr. Cyril Brulebois will handle this issue better. :-)
(I thought that creating fake fontconfig cache when building image, then decompress compressed font dynamically might work as just an idea, but it didn't work.)
If you would like to tackle fixing d-i issues as a newbie, it might be better to execute "make reallyclean" before rebuilding image not to fall-in pitfalls.
Metal from Heaven is industrial-era secondary-world fantasy with a
literary bent. It is a complete story in one book, and I would be very
surprised by a sequel. Clarke previously wrote the Scapegracers
young-adult trilogy, which got excellent reviews and a few award
nominations, as H.A. Clarke. This is his first adult novel.
Know I adore you. Look out over the glow. The cities sundered, their
machines inverted, mountains split and prairies blazing, that long
foreseen Hereafter crowning fast. This calamity is a promise made to
you. A prayer to you, and to your shadow which has become my second
self, tucked behind my eye and growing in tandem with me, pressing
outwards through the pupil, the smarter, truer, almost bursting reason
for our wrath. Do not doubt me. Just look. Watch us rise as the sun
comes up over the beauty. The future stains the bleakness so pink.
When my violence subsides, we will have nothing, and be champions.
Marney Honeycutt is twelve years old, a factory worker, and lustertouched.
She works in the Yann I. Chauncey Ichorite Foundry in Ignavia City,
alongside her family and her best friend, shaping the magical metal
ichorite into the valuable industrial products of a new age of commerce
and industry. She is the oldest of the lustertouched, the children born to
factory workers and poisoned by the metal. It has made her allergic, prone
to fits at any contact with ichorite, but also able to exert a strange
control over the metal if she's willing to pay the price of spasms and
hallucinations for hours afterwards.
As Metal from Heaven opens, the workers have declared a strike. Her
older sister is the spokesperson, demanding shorter hours, safer working
conditions, and an investigation into the health of the lustertouched
children. Chauncey's response is to send enforcer snipers to kill the
workers, including the entirety of her family.
The girl sang, "Unalone toward dawn we go, toward the glory of the new
morning."
An enforcer shot her in the belly, and when she did not fall, her
head.
Marney survives, fleeing into the city, swearing an impossible personal
revenge against Yann Chauncey. An act of charity gets her a ticket on a
train into the countryside. The woman who bought her ticket is a bandit
who is on the train to rob it. Marney's ability to control ichorite allows
her to help the bandits in return, winning her a place with the
Highwayman's Choir who have been preying on the shipments of the rich and
powerful and then disappearing into the hills.
The Choir's secret is that the agoraphobic and paranoid Baron of the
Fingerbluffs is dead and has been for years. He was killed by his staff,
Hereafterist idealists, who have turned his remote territory into an
anarchist commune and haven for pirates and bandits. This becomes Marney's
home and the Choir becomes her family, but she never forgets her oath of
revenge or the childhood friend she left behind in the piles of bodies and
to whom this story is narrated.
First, Clarke's writing is absolutely gorgeous.
We scaled the viny mountain jags at Montrose Barony's legal edge, the
place where land was and wasn't Ignavia, Royston, and Drustland alike.
There was a border but it was diffuse and hallucinatory, even more so
than most. On legal papers and state maps there were harsh lines that
squashed topography and sanded down the mountains into even hills in
planter's rows, but here among the jutting rocks and craggy heather,
the ground was lineless.
The rhythm of it, the grasp of contrast and metaphor, the word choice!
That climactic word "lineless," with its echo of limitless. So good.
Second, this is the rarest of books: a political fantasy that takes class
and religion seriously and uses them for more than plot drivers. This is
not at all our world, and the technology level is somewhat ambiguous, but
the parallels to the Gilded Age and Progressive Era are unmistakable. The Hereafterists that Marney joins
are political anarchists, not in the sense of alternative governance
structures and political theory sanitized for middle-class liberals, but
in the sense of Emma
Goldman and Peter
Kropotkin. The society they have built in the Fingerbluffs is temporary,
threatened, and contingent, but it is sincere and wildly popular among the
people who already lived there.
Even beyond politics, class is a tangible force in this book. Marney is a
factory worker and the child of factory workers. She barely knows how to
read and doesn't magically learn over the course of the book. She has
friends who are clever in the sense rewarded by politics and nobility, who
navigate bureaucracies and political nuance, but that is not Marney's
world. When, towards the end of the book, she has to deal with a gathering
of high-class women, the contrast is stark, and she navigates that
gathering only by being entirely unexpected.
Perhaps the best illustration of the subtlety of this is the terminology
in the book for lesbian. Marney is a crawly, which is a slur thrown at
people like her (and one of the rare fictional slurs that work exactly as
the author intended) but is also simply what she calls herself. Whether or
not it functions as a slur depends on context, and the context is never
hard to understand. The high-class lesbians she meets later are Lunarists,
and react to crawly as a vile and insulting word. They use language to
separate themselves from both the insult and from the social class that
uses it. Language is an indication of culture and manners and therefore of
morality, unlike deeds, which admit endless justifications.
Conversation was fleeting. Perdita managed with whomever stood near
her, chipper about every prettiness she saw, the flitting butterflies,
the dappled light between the leaves, the lushness and the fragrance
of untamed land, and her walking companions took turns sharing in her
delight. It was infectious, how happy she was. She was going to
slaughter millions. She was going to skip like this all the while.
The handling of religion is perhaps even better. Marney was raised a
Tullian, which sits alongside two other fleshed-out fictional religions
and sketches of several more. Tullians tend to be conservative and
patriarchal, and Marney has a realistically complicated relationship with
faith: sticking with some Tullian worship practices and gestures because
they're part of who she is, feeling a kinship to other Tullians,
discarding beliefs that don't fit her, and revising others.
Every major religion has a Hereafterist spin or reinterpretation that
upends or reverses the parts of the religion that were used to prop up the
existing social order and brings it more in line with Hereafterist ideals.
We see the Tullian Hereafterist variation in detail, and as someone who
has studied a lot of methods of reinterpreting Christianity, I was
impressed by how well Clarke invents both a belief system and its
revisionist rewrite. This is exactly how religions work in human history,
but one almost never sees this subtlety in fantasy novels.
Marney's allergy to ichorite causes her internal dialogue to dissolve into
hallucinatory synesthesia when she's manipulating or exposed to it. Since
that's most of the book, substantial portions read like drug trips with
growing body horror. I normally hate this type of narration, so it's a
sign of just how good Clarke's writing is that I tolerated it and even
enjoyed parts. It helps that the descriptions are irreverent and often
surprising, full of unexpected metaphors and sudden turns. It's very hard
not to quote paragraph after paragraph of this book.
Clarke is also doing a lot with gender that I don't feel qualified to
comment in detail on, but it would not surprise me to see this book in the
Otherwise Award recommendation list. I
can think of three significant male characters, all of whom are well-done,
but every other major character is female by at least some gender
definition. Within that group, though, is huge gender diversity of the
complicated and personal type that doesn't force people into defined
boxes. Marney's sexuality is similarly unclassified and sometimes
surprising. My one complaint is that I thought the sex scenes (which, to
warn, are often graphic) fell into the literary fiction trap of being
described so closely and physically that it didn't feel like anyone
involved was actually enjoying themselves. (This is almost certainly a
matter of personal taste.)
I had absolutely no idea how Clarke was going to end this book, and the
last couple of chapters caught me by surprise. I'm still not sure what I
think about the climax. It's not the ending that I wanted, but one of the
merits of this book is that it never did what I thought I wanted and yet
made me enjoy the journey anyway. It is, at least, a genre ending, not a
literary ending: The reader gets a full explanation of what is going on,
and the setting is not static the way that it so often is in literary
fiction. The characters can change the world, for good or for ill. The
story felt frustrating and incomplete when I first finished it, but I
haven't stopped thinking about this book and I think I like the shape of
it a bit more now. It was certainly unexpected, at least by me.
Clarke names Dhalgren as one of their influences in the
acknowledgments, and yes, Metal from Heaven is that kind of book.
This is the first 2024 novel I've read that felt like the kind of book
that should be on award shortlists. I'm not sure it was entirely
successful, and there are parts of it that I didn't like or that weren't
for me, but it's trying to do something different and challenging and
uncomfortable, and I think it mostly worked. And the writing is so good.
She looked like a mythic princess from the old woodcuts, who ruled
nature by force of goodness and faith and had no legal power.
Metal from Heaven is not going to be everyone's taste. If you do
not like literary fantasy, there is a real chance that you will hate this.
I am very glad that I read it, and also am going to take a significant
break from difficult books before I tackle another one. But then I'm
probably going to try the Scapegracers series, because Clarke is an author
I want to follow.
Content notes: Explicit sex, including sadomasochistic sex. Political
violence, mostly by authorities. Murdered children, some body horror, and
a lot of serious injuries and death.
Rating: 8 out of 10
Beyond the Fringe is a military science fiction short story
collection set in the same universe as Artifact Space. It is intended as a bridge between that novel and
its sequel, Deep Black.
Originally I picked this up for exactly the reason it was published: I was
eagerly awaiting Deep Black and thought I'd pass the time with some
filler short fiction. Then, somewhat predictably, I didn't get around to
reading it until after Deep Black was already out. I still read
this collection first, partly because I'm stubborn about reading things in
publication order but mostly to remind myself of what was going on in
Artifact Space before jumping into the sequel.
My stubbornness was satisfied. My memory was not; there's little to no
background information here, and I had to refresh my memory of the
previous book anyway to figure out the connections between these stories
and the novel.
My own poor decisions aside, these stories are... fine, I guess? They're
competent military SF short fiction, mostly more explicitly military than
Artifact Space. All of them were reasonably engaging. None of them
were that memorable or would have gotten me to read the series on their
own. They're series filler, in other words, offering a bit of setup for
the next novel but not much in the way of memorable writing or plot.
If you really want more in this universe, this exists, but my guess (not
having read Deep Black) is that it's entirely skippable.
"Getting Even": A DHC paratrooper lands on New Shenzen, a
planet that New Texas is trying to absorb into the empire it is attempting
to build. He gets captured by one group of irregulars and then runs into
another force with an odd way of counting battle objectives.
I think this exists because Cameron wanted to tell a version of a World
War II story he'd heard, but it's basically a vignette about a weird
military unit with no real conclusion, and I am at a loss as to the point
of the story. There isn't even much in the way of world-building. I'm
probably missing something, but I thought it was a waste of time. (4)
"Partners": The DHC send a planetary exobiologist to New Texas
as a negotiator. New Texas is aggressively, abusively capitalist and is
breaking DHC regulations on fair treatment of labor. Why send a planetary
exobiologist is unclear (although probably ties into the theme of this
collection that the reader slowly pieces together); maybe it's because
he's originally from New Texas, but more likely it's because of his
partner. Regardless, the New Texas government are exploitative assholes
with delusions of grandeur, so the negotiations don't go very smoothly.
This was my favorite story of the collection just because I enjoy people
returning rudeness and arrogance to sender, but like a lot of stories in
this collection it doesn't have much of an ending. I suspect it's mostly
setup for Deep Black. (7)
"Dead Reckoning": This is the direct fallout of the previous
story and probably has the least characterization of this collection.
It covers a few hours of a merchant ship having to make some fast
decisions in a changing political situation. The story is framed around a
veteran spacer and his new apprentice, although even that frame is mostly
dropped once the action starts. It was suspenseful and enjoyable enough
while I was reading it, but it's the sort of story that you forget
entirely after it's over. (6)
"Trade Craft": Back on a planet for this story, which follows
an intelligence agent on a world near but not inside New Texas's area of
influence. I thought this was one of the better stories of the collection
even though it's mostly action. There are some good snippets of
characterization, an interesting mix of characters, and some well-written
tense scenes. Unfortunately, I did not enjoy the ending for reasons that
would be spoilers. Otherwise, this was good but forgettable. (6)
"One Hour": This is the first story with a protagonist outside
of the DHC and its associates. It instead follows a PTX officer (PTX is a
competing civilization that features in Artifact Space) who has
suspicions about what his captain is planning and recruits his superior
officer to help him do something about it.
This is probably the best story in the collection, although I personally
enjoyed "Partners" a smidgen more. Shunfu, the first astrogator who is
recruited by the protagonist, is a thoroughly enjoyable character, and the
story is tense and exciting all the way through. For series readers, it
also adds some depth to events in Artifact Space (if the reader
remembers them), and I suspect will lead directly into Deep Black.
(7)
"The Gifts of the Magi": A kid and his mother, struggling
asteroid miners with ancient and malfunctioning equipment, stumble across a
DHC ship lurking in the New Texas system for a secret mission. This is a
stroke of luck for the miners, since the DHC is happy to treat the serious
medical problems of the mother without charging unaffordable fees the way
that the hyper-capitalist New Texas doctors would. It also gives the
reader a view into DHC's covert monitoring of the activities of New Texas
that all the stories in this collection have traced.
As you can tell from the title, this is a Christmas story. The crew of
the DHC ship is getting ready to celebrate Alliday, which they claim rolls
all of the winter holidays into one. Just like every other effort to do
this, no, it does not, it just subsumes them all into Christmas with some
lip service to other related holidays. I am begging people to realize
that other religions often do not have major holidays in December, and
therefore you cannot include everyone by just declaring December to be
religious holiday time and thinking that will cover it.
There is the bones of an interesting story here. The covert mission setup
has potential, the kid and his mother are charming if cliched, there's a
bit of world-building around xenoglas (the magical alien material at the
center of the larger series plot), and there's a lot of foreshadowing for
Deep Black. Unfortunately, this is too obviously a side story and a
setup story: none of this goes anywhere satisfying, and along the way the
reader has to endure endless rather gratuitous Christmas references, such
as the captain working on a Nutcracker ballet performance for the ship
talent show.
This isn't bad, exactly, but it rubbed me the wrong way. If you love
Christmas stories, you may find it more agreeable. (5)
Rating: 6 out of 10
I haven't made one of these posts since... last year? Good lord. I've
therefore already read and reviewed a lot of these books.
Kemi Ashing-Giwa The Splinter in the Sky (sff)
Moniquill Blackgoose To Shape a Dragon's Breath (sff)
Ashley Herring Blake Delilah Green Doesn't Care (romance)
Ashley Herring Blake Astrid Parker Doesn't Fail (romance)
Ashley Herring Blake Iris Kelly Doesn't Date (romance)
Molly J. Bragg Scatter (sff)
Sarah Rees Breenan Long Live Evil (sff)
Michelle Browne And the Stars Will Sing (sff)
Steven Brust Lyorn (sff)
Miles Cameron Beyond the Fringe (sff)
Miles Cameron Deep Black (sff)
Haley Cass Those Who Wait (romance)
Sylvie Cathrall A Letter to the Luminous Deep (sff)
Ta-Nehisi Coates The Message (non-fiction)
Julie E. Czerneda To Each This World (sff)
Brigid Delaney Reasons Not to Worry (non-fiction)
Mar Delaney Moose Madness (sff)
Jerusalem Demsas On the Housing Crisis (non-fiction)
Michelle Diener Dark Horse (sff)
Michelle Diener Dark Deeds (sff)
Michelle Diener Dark Minds (sff)
Michelle Diener Dark Matters (sff)
Elaine Gallagher Unexploded Remnants (sff)
Bethany Jacobs These Burning Stars (sff)
Bethany Jacobs On Vicious Worlds (sff)
Micaiah Johnson Those Beyond the Wall (sff)
T. Kingfisher Paladin's Faith (sff)
T.J. Klune Somewhere Beyond the Sea (sff)
Mark Lawrence The Book That Wouldn't Burn (sff)
Mark Lawrence The Book That Broke the World (sff)
Mark Lawrence Overdue (sff)
Mark Lawrence Returns (sff collection)
Malinda Lo Last Night at the Telegraph Club (historical)
Jessie Mihalik Hunt the Stars (sff)
Samantha Mills The Wings Upon Her Back (sff)
Lyda Morehouse Welcome to Boy.net (sff)
Cal Newport Slow Productivity (non-fiction)
Naomi Novik Buried Deep and Other Stories (sff collection)
Claire O'Dell The Hound of Justice (sff)
Keanu Reeves & China Mi ville The Book of Elsewhere (sff)
Kit Rocha Beyond Temptation (sff)
Kit Rocha Beyond Jealousy (sff)
Kit Rocha Beyond Solitude (sff)
Kit Rocha Beyond Addiction (sff)
Kit Rocha Beyond Possession (sff)
Kit Rocha Beyond Innocence (sff)
Kit Rocha Beyond Ruin (sff)
Kit Rocha Beyond Ecstasy (sff)
Kit Rocha Beyond Surrender (sff)
Kit Rocha Consort of Fire (sff)
Geoff Ryman HIM (sff)
Melissa Scott Finders (sff)
Rob Wilkins Terry Pratchett: A Life with Footnotes (non-fiction)
Gabrielle Zevin Tomorrow, and Tomorrow, and Tomorrow
(mainstream)
That's a lot of books, although I think I've already read maybe a third of
them? Which is better than I usually do.