<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>KV Tech Tips</title>
  <subtitle>Troubleshooting and How-Tos.</subtitle>
  <link href="https://kvibber.com/tech-tips/feed.xml" rel="self"/>
  <link href="https://kvibber.com/tech-tips/"/>
  <icon>https://kvibber.com/tech-tips/images/keyboard-180.jpg</icon>
  <updated>2026-03-13T00:39:43Z</updated>
  <id>https://kvibber.com/tech-tips/</id>
  <author>
    <name>Kelson Vibber</name>
    <email>techtips@kvibber.com</email>
    <uri>https://kvibber.com</uri>
  </author>
  
  
  
  <entry>
    <title>Connect macOS Calendar, Contacts and Reminders to NextCloud</title>
    <link href="https://kvibber.com/tech-tips/mac-nextcloud-cal-card/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="apple-mac"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="nextcloud"/><category term="macos"/><category term="calendar"/><category term="contacts"/><category term="to-do-list"/><category term="productivity"/><category term="self-hosting"/>
    <summary>Current versions of macOS hide the options to add a CalDAV or CardDAV account behind a couple of &#39;more...&#39; links, and it still asks for an email address when you get there. Or you can download a Device Management profile if you know where to look.</summary>
    <updated>2026-03-13T00:39:43Z</updated>
    <id>https://kvibber.com/tech-tips/mac-nextcloud-cal-card/</id>
    <content type="html">
    &lt;p&gt;&lt;a href=&quot;https://hyperborea.org/reviews/software/nextcloud-calendar/&quot;&gt;Nextcloud Calendar&lt;/a&gt; and Contacts are solid cross-platform alternatives to iCloud’s equivalents, and Tasks is good enough I’ve been using it for several years.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;The main problem with Nextcloud Tasks is its &lt;a href=&quot;https://kvibber.com/tech-tips/nextcloud-tasks/&quot;&gt;flaky handling of recurring tasks&lt;/a&gt;, though if you use an app like Reminders that &lt;em&gt;does&lt;/em&gt; understand repeating, the server can (mostly) handle it.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;On macOS, System Settings &amp;gt; Internet Accounts&lt;/strong&gt; manages logins for all the built-in applications like &lt;a href=&quot;https://hyperborea.org/reviews/software/apple-mail/&quot;&gt;Apple Mail&lt;/a&gt;, Calendar, Reminders and Contacts. Setting these up with Nextcloud is easy, but it’s not &lt;em&gt;intuitive&lt;/em&gt;, because Apple has been optimizing the setup process for all-in-one services like iCloud, Google or Microsoft.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;The Nextcloud desktop app isn’t used for this, since it mainly handles file sync.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2&gt;Option 1: Download a Device Profile&lt;/h2&gt;
&lt;p&gt;On your Nextcloud server’s website, open your account settings, then go to the &lt;strong&gt;Mobile &amp;amp; Desktop&lt;/strong&gt; section. Below the app store links, look for &lt;strong&gt;“Download macOS/iOS configuration profile.”&lt;/strong&gt; That link will download a config with all the info except your password. (You &lt;a href=&quot;https://kvibber.com/tech-tips/nextcloud-sync-token/&quot;&gt;should generate an app-specific one&lt;/a&gt;, but it’s not necessary.)&lt;/p&gt;
&lt;p&gt;On your Mac, open &lt;strong&gt;System Settings&lt;/strong&gt;, go to &lt;strong&gt;General &amp;gt; Device Management&lt;/strong&gt; and approve the Nextcloud profile. It’ll ask for the password twice because you’re still technically logging into two services, one for calendar and one for contacts.&lt;/p&gt;
&lt;h2&gt;Option 2: Add the Accounts Manually&lt;/h2&gt;
&lt;p&gt;If you don’t want to use Device Management, or run into trouble getting it to work, you can still set up the accounts in &lt;strong&gt;System Settings &amp;gt; Internet Accounts&lt;/strong&gt;. The process is simple, if a little misleading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First:&lt;/strong&gt; Starting with macOS 26 (Tahoe), it only asks you for an &lt;em&gt;email address&lt;/em&gt; when you press Add Account. To add a contacts/calendar account:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on &lt;strong&gt;“choose from a list.”&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Scroll down and click on &lt;strong&gt;“Add other account…”&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Now&lt;/em&gt; you can add a &lt;strong&gt;CalDAV&lt;/strong&gt; (Calendar/Reminders) or &lt;strong&gt;CardDAV&lt;/strong&gt; (Contacts) account.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Alternatively:&lt;/strong&gt; go through the Apple Calendar or Contacts apps’ settings and add the account there. It’ll still get added to the central set of accounts.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;This is &lt;em&gt;not&lt;/em&gt; the Accounts item on the application menu, which just brings up System Settings/Internet Accounts and puts you right back where we started, but the Accounts tab inside the applications’ Settings window.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Second:&lt;/strong&gt; It &lt;em&gt;still&lt;/em&gt; asks you for an email address when you tell it to add one of those account types!&lt;/p&gt;
&lt;p&gt;You can switch from &lt;strong&gt;Automatic to Manual&lt;/strong&gt; in the dropdown, and it’ll ask for a username and server… or you can just enter the equivalent of &lt;code&gt;username@server.example.com&lt;/code&gt; (even if it isn’t a real email address) and your (&lt;a href=&quot;https://kvibber.com/tech-tips/nextcloud-sync-token/&quot;&gt;preferably app-specific&lt;/a&gt;) password, and it’ll find the right details for your server.&lt;/p&gt;
&lt;p&gt;Easy, but not obvious!&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;The last time I did this was a few macOS versions back, and I vaguely recall having to look up at least one of the specific URLs. Though it’s possible I’m just getting that mixed up with old versions of &lt;a href=&quot;https://hyperborea.org/reviews/software/thunderbird/&quot;&gt;Thunderbird&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/mac-nextcloud-cal-card/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Using Unicode Half-Stars Symbols in Ratings</title>
    <link href="https://kvibber.com/tech-tips/half-stars/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="web-development"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="css"/><category term="fonts"/>
    <summary>Filled and outlined stars have been in Unicode forever. Half-stars have been available since Unicode 11 (2018), but font support is still spotty. Fortunately you can embed a font on your website that *does* support the symbols and rate something four and a half stars.</summary>
    <updated>2026-03-03T01:01:17Z</updated>
    <id>https://kvibber.com/tech-tips/half-stars/</id>
    <content type="html">
    &lt;p&gt;When I started &lt;a href=&quot;https://hyperborea.org/reviews/&quot;&gt;collecting reviews in one section&lt;/a&gt; of my website, I decided to stick with the goals I had here on the Tech Tips section: Keep the pages small, avoid loading scripts or extra images where styles or font symbols would do. So I kept using emoji for category icons, and used the outlined and filled star symbols (☆★) for ratings. They’ve been in Unicode forever, so they’re supported almost everywhere.&lt;/p&gt;
&lt;h2&gt;Halfway There&lt;/h2&gt;
&lt;p&gt;Every once in a while, I really want to rate something &lt;em&gt;between&lt;/em&gt; a whole number of stars. I let it round down for a while until I went looking to see if there were half-filled star symbols. And there are! Half-stars and half-filled stars (in both directions) were &lt;a href=&quot;https://www.righto.com/2016/10/inspired-by-hn-comment-four-half-star.html&quot;&gt;proposed in 2016&lt;/a&gt; and &lt;a href=&quot;https://www.unicode.org/charts/PDF/Unicode-11.0/U110-2B00.pdf&quot;&gt;added to Unicode 11 in 2018&lt;/a&gt;. You can see them here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⯨⯩⯪⯫&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;…or maybe you can’t, because even after eight years, font support for them is &lt;em&gt;still&lt;/em&gt; spotty.&lt;/p&gt;
&lt;p&gt;As of March 2026:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 11 shows the symbols.&lt;/li&gt;
&lt;li&gt;Linux distros might, depending on what fonts are installed. Modern distros at least &lt;em&gt;have&lt;/em&gt; fonts that support these symbols, in packages like noto-fonts (Arch), fonts-noto-core (Debian) or google-noto-sans-symbols-2-fonts (Fedora), but whether they’re installed by default seems to vary.&lt;/li&gt;
&lt;li&gt;Windows 10, macOS/iOS 26 and Android don’t, even though they include newer emoji than Unicode 11.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So if you’re trying to use these on a web page, it’s really hit and miss whether your readers will be able to see the half-star symbols or not.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;It would be nice if you could, in HTML, &lt;a href=&quot;https://notes.kvibber.com/@kelson/statuses/01JRKBPXDMXTDKRREVBXKWAKAK&quot;&gt;provide a fallback for font glyphs&lt;/a&gt; that aren’t available (like how &lt;code&gt;alt&lt;/code&gt; was originally supposed to replace an image entirely if the image couldn’t be loaded), but as near as I can that’s never been seriously proposed.&lt;/p&gt;
&lt;/aside&gt; 
&lt;p&gt;The good news is, you can embed a font on your page (or app) that &lt;em&gt;does&lt;/em&gt; support the missing symbols! &lt;a href=&quot;https://fonts.google.com/noto/specimen/Noto+Sans+Symbols+2/&quot;&gt;Noto Sans Symbols 2&lt;/a&gt; contains the full set, and can be used freely. Embedding that font and using it for the ratings solves the problem.&lt;/p&gt;
&lt;blockquote class=&quot;stars&quot;&gt; ⯨⯩⯪⯫&lt;/blockquote&gt;
&lt;p&gt;That said, it &lt;em&gt;is&lt;/em&gt; an extra 200 KB or so, which is a bit overkill for adding one very simple bit of line art. (See the &lt;a href=&quot;https://kvibber.com/tech-tips/half-stars/#alternatives&quot;&gt;Alternatives&lt;/a&gt; section below.)&lt;/p&gt;
&lt;h2&gt;Adding Font Support&lt;/h2&gt;
&lt;p&gt;The simplest thing to do, if you’re not worried about Google potentially tracking visitors to your site (see &lt;a href=&quot;https://kvibber.com/tech-tips/half-stars/#self-hosting&quot;&gt;self-hosting&lt;/a&gt; below for an alternative), is just embed the font from Google by putting this in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of your page:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
&amp;lt;link rel=&amp;quot;preconnect&amp;quot; href=&amp;quot;https://fonts.googleapis.com&amp;quot;&amp;gt;
&amp;lt;link rel=&amp;quot;preconnect&amp;quot; href=&amp;quot;https://fonts.gstatic.com&amp;quot; crossorigin&amp;gt;
&amp;lt;link href=&amp;quot;https://fonts.googleapis.com/css2?family=Noto+Sans+Symbols+2&amp;amp;display=swap&amp;quot; rel=&amp;quot;stylesheet&amp;quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in your stylesheet, write something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.stars {font-family: &amp;quot;Noto Sans Symbols 2&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you can write your star ratings like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;span class=&quot;stars&quot;&amp;gt;&lt;span class=&quot;stars&quot;&gt;★★★⯪☆&lt;/span&gt;&amp;lt/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;span class=&quot;stars&quot;&gt;★★★⯪☆&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;I actually go a bit further on mine for accessibility and &lt;a href=&quot;https://microformats.org/wiki/h-review&quot;&gt;microformats&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;abbr class=&quot;stars p-rating&quot;
  title=&quot;3.5 stars out of 5&quot;
  aria-label=&quot;3.5 stars out of 5.&quot;
  value=&quot;3.5&quot;&amp;gt;&lt;span class=&quot;stars&quot;&gt;★★★⯪☆&lt;/span&gt;&amp;lt;/abbr&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;abbr class=&quot;stars p-rating&quot; value=&quot;3.5&quot; title=&quot;3.5 stars out of 5&quot; aria-label=&quot;3.5 stars out of 5.&quot;&gt;★★★⯪☆&lt;/abbr&gt;&lt;/blockquote&gt;
&lt;h2&gt;&lt;a name=&quot;html-codes&quot;&gt;&lt;/a&gt;HTML Codes&lt;/h2&gt;
&lt;p&gt;If you’re writing on a system that doesn’t support all the star characters natively, you can use numeric HTML entities. It’ll be just as unreadable as the tofu, but you’ll be able to tell them apart from each other.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;#9733;&lt;/code&gt; or &lt;code&gt;&amp;amp;#x2605;&lt;/code&gt;	&lt;span class=&quot;stars&quot;&gt;★&lt;/span&gt;	Black star&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;#9734;&lt;/code&gt; or &lt;code&gt;&amp;amp;#x2606;&lt;/code&gt;	&lt;span class=&quot;stars&quot;&gt;☆&lt;/span&gt;	White Star&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;#11240;&lt;/code&gt; or &lt;code&gt;&amp;amp;#x2BE8;&lt;/code&gt;	&lt;span class=&quot;stars&quot;&gt;⯨&lt;/span&gt;	Left half black star&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;#11241;&lt;/code&gt; or &lt;code&gt;&amp;amp;#x2BE9;&lt;/code&gt;	&lt;span class=&quot;stars&quot;&gt;⯩&lt;/span&gt;	Right half black star&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;#11242;&lt;/code&gt; or &lt;code&gt;&amp;amp;#x2BEA;&lt;/code&gt;	&lt;span class=&quot;stars&quot;&gt;⯪&lt;/span&gt;	Star with left half black&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;#11243;&lt;/code&gt; or &lt;code&gt;&amp;amp;#x2BEB;&lt;/code&gt;	&lt;span class=&quot;stars&quot;&gt;⯫&lt;/span&gt;	Star with right half black&lt;/li&gt;
&lt;/ul&gt;
&lt;aside&gt;&lt;p&gt;Unicode naming schemes are rooted in print, so a filled-in star is a black star, and an outline is a white star, assuming black ink on a white page.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2&gt;&lt;a name=&quot;self-hosting&quot;&gt;&lt;/a&gt;Self-Hosting the Font&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developers.google.com/fonts/faq/privacy&quot;&gt;Google Fonts Privacy Policy&lt;/a&gt; states that they don’t do any tracking on the font requests and keep them completely separate from any account-related traffic. But if you want to be &lt;em&gt;absolutely certain&lt;/em&gt;, or need to comply with regulations like GDPR, you can host your own copy.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;The Noto fonts are licenced for free reuse and embedding, and the Google Fonts site explicitly says you can self-host (but would rather you didn’t).&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;They don’t make it &lt;em&gt;easy&lt;/em&gt;, though.&lt;/p&gt;
&lt;h3&gt;Option 1: Download and Convert from TTF&lt;/h3&gt;
&lt;p&gt;If you download the font from Google Fonts, you get the complete TrueType font, which in this case is about 6 times as big as the WOFF2 font for web embedding. The .zip at &lt;a href=&quot;https://github.com/notofonts/symbols&quot;&gt;the font’s GitHub page&lt;/a&gt; also includes smaller versions, closer to 400KB, in the “hinted” and “unhinted” folders. (In this case they’re the same, but for other fonts you’ll probably want the version with hinting.)&lt;/p&gt;
&lt;p&gt;You can use an online TrueType to WOFF2 converter, or you can use an offline tool.&lt;/p&gt;
&lt;p&gt;The command-line &lt;a href=&quot;https://github.com/google/woff2&quot;&gt;woff2_compress&lt;/a&gt; tool is available in Homebrew for macOS and various Linux distributions in the woff2 (&lt;a href=&quot;https://hyperborea.org/reviews/software/debian/&quot;&gt;Debian&lt;/a&gt;, &lt;a href=&quot;https://hyperborea.org/reviews/software/alpine-linux/&quot;&gt;Alpine&lt;/a&gt;, Homebrew, etc) or woff2-tools (&lt;a href=&quot;https://hyperborea.org/reviews/software/fedora/&quot;&gt;Fedora&lt;/a&gt;) packages.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;woff2_compress NotoSansSymbols2-Regular.ttf
&lt;/code&gt;&lt;/pre&gt;
&lt;aside&gt;&lt;p&gt;These days, &lt;a href=&quot;https://caniuse.com/woff2&quot;&gt;WOFF2 is effectively baseline&lt;/a&gt; across modern web browsers, so you don’t need to include any fallback formats anymore.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3&gt;Option 2: Find a Pre-Built WOFF2 file&lt;/h3&gt;
&lt;p&gt;Or you can grab a copy of the WOFF2 file from Google Fonts. The simplest way is to open their font stylesheet (the one in the third &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; above) directly, scroll down to the &lt;code&gt;/* symbols */&lt;/code&gt; section, copy the URL from that, and save the .woff2 file. Preferably giving it a name you can recognize later on.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;All the sections point to the same font file right now, but if they ever split up the hosted file, you’ll want to make sure you get the one with general symbols.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3&gt;Embedding Your Copy&lt;/h3&gt;
&lt;p&gt;You won’t need the entire set of font definitions and Unicode ranges, because you’re using it in narrow circumstances. And you won’t need the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; elements pointing to Google. Though you may need to keep the &lt;code&gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;/code&gt; depending on your hosting setup. In any case, you’ll want to add this to your stylesheet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@font-face {
  font-family: &amp;quot;Noto Sans Symbols 2&amp;quot;;
  font-display: swap;
  src: url(/path/to/your/copy/of/NotoSansSymbols2-Regular.woff2);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;font-display: swap&lt;/code&gt; tells browsers to keep rendering the page if it takes a while to load the font, and swap it in when it’s ready.&lt;/p&gt;
&lt;p&gt;On larger pages especially, you may also want to &lt;a href=&quot;https://kvibber.com/tech-tips/webfont-doubled/&quot;&gt;preload the font&lt;/a&gt; so the browser will start downloading it as soon as it can, instead of waiting until it’s downloaded and parsed the stylesheet.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;alternatives&quot;&gt;&lt;/a&gt;Alternatives&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Use images instead of font symbols. (PNGs or SVGs would be tiny.)&lt;/li&gt;
&lt;li&gt;Use an icon font like &lt;a href=&quot;https://fontawesome.com/icons/star-half-stroke?f=classic&amp;amp;s=solid&quot;&gt;Font Awesome&lt;/a&gt; that provides its own symbols. (Download size is comparable to embedding Noto Sans Symbol 2, but you can also use their icons as SVGs, which can be a &lt;em&gt;lot&lt;/em&gt; smaller if you only need a handful.)&lt;/li&gt;
&lt;li&gt;Create a subset of the font (Either Noto or FontAwesome) that leaves out everything but the symbols needed.&lt;/li&gt;
&lt;li&gt;Embed the font, but only on the individual pages that need it. (That’s what I’ve done for this page.)&lt;/li&gt;
&lt;li&gt;Use a more widely-supported symbol like ½ instead. (This is what I initially did on my reviews.)&lt;/li&gt;
&lt;li&gt;Use a fraction symbol, and then use JavaScript to check whether the half-star is supported in the current font, and swap it in if it’s available. (Or the other way around, but this is more backward compatible.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then again, ~200 KB is a fraction of the &lt;a href=&quot;https://www.pingdom.com/blog/webpages-are-getting-larger-every-year-and-heres-why-it-matters/&quot;&gt;average page size&lt;/a&gt; these days. More than a drop in the bucket, but hardly a dealbreaker. Even if it is 10 times the size &lt;em&gt;this&lt;/em&gt; page would be without it.&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/half-stars/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Select All of a Code Sample Using Minimal JS</title>
    <link href="https://kvibber.com/tech-tips/select-all/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="web-development"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="usability"/><category term="accessibility"/><category term="javascript"/>
    <summary>A short (~10 lines) JavaScript fragment to select an entire code snippet when someone clicks, taps, or presses a key on it.</summary>
    <updated>2026-02-25T15:43:15Z</updated>
    <id>https://kvibber.com/tech-tips/select-all/</id>
    <content type="html">
    &lt;p&gt;I’ve got a lot of code samples on here, plus the &lt;a href=&quot;https://kvibber.com/tech-tips/bookmarklets/&quot;&gt;bookmarklets collection&lt;/a&gt;. It’s not hard so select the whole block with a mouse, but it’s not exactly &lt;em&gt;easy&lt;/em&gt; either. (You can triple-click to select a paragraph, but code samples are rarely paragraphs.)&lt;/p&gt;
&lt;p&gt;You can do this with various JavaScript frameworks, but one of my goals on this site is to keep the bandwidth and processing minimal. One HTML file per article, one shared CSS file. I figured  I should be able to do this with vanilla JavaScript now.&lt;/p&gt;
&lt;p&gt;Turns out it’s pretty simple, and if you only want to use it with mouse clicks and touch taps, it’s only 4 lines of JavaScript (plus closing braces/parentheses). Here I’m setting it on all code elements that are inside pre blocks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-JavaScript&quot;&gt;const codeSamples = document.querySelectorAll(&amp;quot;pre code&amp;quot;);
codeSamples.forEach( (sample) =&amp;gt; {
  sample.addEventListener(&amp;quot;click&amp;quot;, (e) =&amp;gt; {
    window.getSelection().selectAllChildren(e.target);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That doesn’t take care of keyboard users, though. You can add a “keypress” event, but &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; isn’t normally focusable by tab. Fortunately it’s easy enough to add an element to the tab order in JavaScript (zero means let the browser decide where to put it), and we already have it looping through the nodes we want to modify.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-JavaScript&quot;&gt;  sample.setAttribute(&amp;quot;tabindex&amp;quot;,0);
  sample.addEventListener(&amp;quot;keypress&amp;quot;, (e) =&amp;gt; {
    window.getSelection().selectAllChildren(e.target);
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the full code fragment is 7 lines of actual code, plus closing braces and comments.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-JavaScript&quot;&gt;// Select the entire contents of a code sample.
const codeSamples = document.querySelectorAll(&amp;quot;pre code&amp;quot;);
codeSamples.forEach( (sample) =&amp;gt; {
  
  // Select everything when clicked.
  sample.addEventListener(&amp;quot;click&amp;quot;, (e) =&amp;gt; {
    window.getSelection().selectAllChildren(e.target);
  });
  
  // Add to tab list and select when a key is pressed.
  sample.setAttribute(&amp;quot;tabindex&amp;quot;,0);
  sample.addEventListener(&amp;quot;keypress&amp;quot;, (e) =&amp;gt; {
    window.getSelection().selectAllChildren(e.target);
  });
  
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach works in modern Chromium, WebKit and Gecko-based web browsers. I haven’t tested how it interacts with screen readers or other accessibility features yet.&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/select-all/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Using the loop_end Hook With Multiple WordPress Loops</title>
    <link href="https://kvibber.com/tech-tips/wp-double-loop-end/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="programming"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="wordpress"/><category term="php"/><category term="classicpress"/>
    <summary>I tried to add some custom navigation at the end of the posts lists using the loop_end hook, but it got added twice. Another plugin was running through the Loop and calling rewind_posts(). To make my code only run after the visible Loop, I picked a hook between the loops and checked did_action() for that hook.</summary>
    <updated>2026-02-05T05:22:30Z</updated>
    <id>https://kvibber.com/tech-tips/wp-double-loop-end/</id>
    <content type="html">
    &lt;p&gt;I recently added some custom navigation to the tag and category pages &lt;a href=&quot;https://hyperborea.org/journal/&quot;&gt;on my blog&lt;/a&gt;. I could have tweaked the tag template on the theme I’m using, or I could have created a child theme (which seems overkill for something this small). Since I already use a functionality plugin for the custom code I use on this site, it made more sense to add it there using &lt;a href=&quot;https://developer.wordpress.org/plugins/hooks/&quot;&gt;WordPress hooks&lt;/a&gt;. That also means the next time I switch themes the new links will still be there.&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;On modern WordPress, it’s probably easier to do this with the &lt;a href=&quot;https://wordpress.com/support/site-editor/&quot;&gt;full site editor&lt;/a&gt;, but that requires blocks and a theme that supports it. &lt;a href=&quot;https://hyperborea.org/reviews/software/classicpress/&quot;&gt;I’m using ClassicPress&lt;/a&gt; on this site, a fork of WordPress that removes block editing, in large part because I &lt;a href=&quot;https://hyperborea.org/reviews/software/wordpress-block-editor/&quot;&gt;can’t stand the block editor&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;The clear approach was to use the &lt;a href=&quot;https://developer.wordpress.org/reference/hooks/loop_end/&quot;&gt;&lt;code&gt;loop_end&lt;/code&gt;&lt;/a&gt; hook, which runs when WordPress (or ClassicPress) finishes the Loop with all the posts for the current page. And it worked! Sort of. It added the link &lt;em&gt;twice&lt;/em&gt;, once at the top of the page and once where it was supposed to.&lt;/p&gt;
&lt;p&gt;It turned out one of the other plugins I use runs through the Loop when building preview cards, then rewinds it so the theme templates can display posts normally.&lt;/p&gt;
&lt;p&gt;OK, how do I tell my custom function to only run on &lt;em&gt;one&lt;/em&gt; iteration of the Loop, and which one?&lt;/p&gt;
&lt;h2&gt;A Janky Solution: Global Variables&lt;/h2&gt;
&lt;p&gt;After searching the WordPress documentation, and searching the web, and not finding anything remotely useful for combining &lt;code&gt;loop_end&lt;/code&gt; and &lt;a href=&quot;https://developer.wordpress.org/reference/functions/rewind_posts/&quot;&gt;&lt;code&gt;rewind_posts()&lt;/code&gt;&lt;/a&gt; (never mind any suggestion for best practices), I decided to go with an old standby: Set a global variable between Loops, and check that variable in my function.&lt;/p&gt;
&lt;p&gt;Where to set the global variable? In this case, the first Loop runs in the HTML head, so I used the &lt;a href=&quot;https://developer.wordpress.org/reference/hooks/wp_body_open/&quot;&gt;&lt;code&gt;wp_body_open&lt;/code&gt;&lt;/a&gt; hook to change the variable state.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Hack to only run my loop_end function when the Loop is running in the page body,
// since it gets run early when building the &amp;lt;head&amp;gt;
global $exampleprefix_building_page;
$exampleprefix_building_page = false;
function exampleprefix_set_building_page() {
	$GLOBALS[&#39;exampleprefix_building_page&#39;] = true;
}
add_action( &#39;wp_body_open&#39;, &#39;exampleprefix_set_building_page&#39; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I checked whether &lt;code&gt;$GLOBALS[&#39;exampleprefix_building_page&#39;]&lt;/code&gt; was true or not in the function I attached to &lt;code&gt;loop_end&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;A Better Solution: did_action()&lt;/h2&gt;
&lt;p&gt;As it turns out, there’s a &lt;em&gt;better&lt;/em&gt; way. True to &lt;a href=&quot;https://meta.wikimedia.org/wiki/Cunningham%27s_Law&quot;&gt;Cunningham’s Law&lt;/a&gt; (the best way to get the right answer is not to post the question, but to post the wrong answer), the first reply to this article suggested that I &lt;strong&gt;use the &lt;a href=&quot;https://developer.wordpress.org/reference/functions/did_action/&quot;&gt;&lt;code&gt;did_action()&lt;/code&gt;&lt;/a&gt; method&lt;/strong&gt; instead of messing around with a global variable. (Thanks, @gmazzap@phpc.social!)&lt;/p&gt;
&lt;p&gt;So now I’m checking for &lt;code&gt;did_action(&#39;wp_body_open&#39;)&lt;/code&gt; (If you have multiple Loops running in the page body, you’ll need to look for another dividing point) and I don’t need to mess around with globals after all!&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;All this writing about the Loop reminds me of &lt;em&gt;Heaven’s Vault&lt;/em&gt;, which I &lt;a href=&quot;https://hyperborea.org/reviews/games/heavens-vault/&quot;&gt;finished replaying&lt;/a&gt; earlier this week! Does this make my blog Ioxian or Elborethian?&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Now, even though &lt;code&gt;loop_end&lt;/code&gt; still gets called twice, my function only adds those links where it’s supposed to. And I won’t have to change it if I remove the plugin that’s running the extra Loop, or change themes (unless the new theme adds &lt;em&gt;more&lt;/em&gt; passes through the Loop), or even switch between ClassicPress and WordPress.&lt;/p&gt;
&lt;h2&gt;Sample code&lt;/h2&gt;
&lt;aside&gt;&lt;p&gt;Remember to always put a unique prefix in any function names or global variables you put in a WordPress/ClassicPress plugin, to avoid collisions with other plugins’ names.&lt;/p&gt;
&lt;/aside&gt;
&lt;pre&gt;&lt;code&gt;// Add link at the end of tag/category archives.
add_action( &#39;loop_end&#39;, &#39;exampleprefix_tag_fullsite&#39; );
function exampleprefix_tag_fullsite( $query ) {
    if ( did_action(&#39;wp_body_open&#39;) &amp;amp;&amp;amp; $query-&amp;gt;is_main_query() &amp;amp;&amp;amp; ( $query-&amp;gt;is_tag() || $query-&amp;gt;is_category() ) ) {
		$obj = $query-&amp;gt;get_queried_object();
    	$slug = $obj-&amp;gt;slug;
        echo &#39;&amp;lt;p&amp;gt;&amp;lt;a rel=&amp;quot;nofollow&amp;quot; href=&amp;quot;https://example.com/tag/&#39; . $slug . &#39;&amp;quot;&amp;gt;All pages site-wide with this tag&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&#39;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/wp-double-loop-end/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Outlook Mangling HTML &lt;pre&gt; Tags</title>
    <link href="https://kvibber.com/tech-tips/outlook-pre/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="programming"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="outlook"/><category term="microsoft"/><category term="email"/><category term="html"/>
    <summary>It&#39;s 2026, and Outlook is still mangling email. It&#39;s collapsing whitespace and line breaks in HTML preformatted text, so you need to fake around it with non-breaking spaces and &amp;lt;br&amp;gt; tags.</summary>
    <updated>2026-01-29T02:12:30Z</updated>
    <id>https://kvibber.com/tech-tips/outlook-pre/</id>
    <content type="html">
    &lt;p&gt;It’s 2026, and I’m still dealing with Outlook rendering quirks.&lt;/p&gt;
&lt;p&gt;I needed to plug a preformatted plain-text table into an HTML email alert. Easy, right? Just wrap it with &lt;code&gt;&amp;lt;pre&amp;gt;...&amp;lt;/pre&amp;gt;&lt;/code&gt;? NOPE! That works in literally every other email client I tested, including Gmail, &lt;a href=&quot;https://hyperborea.org/reviews/software/thunderbird/&quot;&gt;Thunderbird&lt;/a&gt; and Roundcube. But &lt;a href=&quot;https://hyperborea.org/reviews/software/outlook/&quot;&gt;not Microsoft Outlook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For whatever reason, Outlook collapses all the whitespace and line breaks. Instead of a nice table, it was a mess. And of course, Outlook was the client that the people who need the alert are using.&lt;/p&gt;
&lt;p&gt;At least it used a monospace font.&lt;/p&gt;
&lt;p&gt;After trying a few CSS overrides that didn’t work, I went with the quick-and-dirty Web 1.0 approach:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Replace all the spaces with &lt;code&gt;&amp;amp;nbsp;&lt;/code&gt; and all the line breaks with &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Standards-compliant email clients handle the non-breaking spaces fine, but they render &lt;code&gt;&amp;lt;br&amp;gt;&#92;n&lt;/code&gt; as two line breaks, so now the HTML is one line, but it looks right when displayed. (Fortunately, the system isn’t using &lt;a href=&quot;https://kvibber.com/tech-tips/lucee-email/&quot;&gt;7bit encoding with its line length limits&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;It’s ridiculous that we still have to do this in 2026 with one of the major tech giants’ flagship email programs for business.&lt;/p&gt;
&lt;h2&gt;So…Why?&lt;/h2&gt;
&lt;p&gt;This is &lt;em&gt;after&lt;/em&gt; Outlook finally shifted away from using Word to render HTML.&lt;/p&gt;
&lt;p&gt;Yeah. Word. As recently as 2023, the desktop version of &lt;a href=&quot;https://www.litmus.com/blog/a-guide-to-rendering-differences-in-microsoft-outlook-clients&quot;&gt;Outlook for Windows &lt;em&gt;still&lt;/em&gt; used Word&lt;/a&gt;. the Mac version had long since switched to using the system renderer, and of course the web version uses whatever browser you’re running. But it was the 2023 “New Outlook” that finally switched across all platforms.&lt;/p&gt;
&lt;p&gt;That means Outlook is deliberately altering the formatting here. It might make sense if you’re rendering an &lt;em&gt;actual&lt;/em&gt; plain-text message that’s mostly paragraphs, but inside a formatted message that explicitly marks a section as preformatted?&lt;/p&gt;
&lt;p&gt;I wonder how long it’s done this. Maybe someone used Copilot to vibe-code this “feature” without considering where a sender would actually use this kind of markup.&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/outlook-pre/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Using BOOX Devices&#39; Page Flip Buttons With Third Party eBook Apps</title>
    <link href="https://kvibber.com/tech-tips/boox-page-buttons/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="mobile"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="android"/><category term="tablet"/><category term="amazon"/><category term="kindle"/><category term="kobo"/><category term="ebook-reader"/><category term="boox"/><category term="hardware"/><category term="e-ink"/>
    <summary>A few eBook apps work with the buttons out of the box, but most need you to enable page-flipping with volume buttons, one app at a time.</summary>
    <updated>2025-12-24T06:02:16Z</updated>
    <id>https://kvibber.com/tech-tips/boox-page-buttons/</id>
    <content type="html">
    &lt;p&gt;The BOOX Page, Palma and Go 7 &lt;a href=&quot;https://www.boox.com/&quot;&gt;e-ink tablet models&lt;/a&gt; feature the return of physical buttons for page flipping, which is a huge improvement in usability over the &lt;a href=&quot;https://hyperborea.org/reviews/products/boox-poke3/&quot;&gt;touchscreen-only devices like the Poke3&lt;/a&gt;. The buttons are on the right in the default display orientation, but if you enable rotating the display, they’ll adjust as expected for left-handed or landscape use.&lt;/p&gt;
&lt;p&gt;Boox’s preinstalled eBook app, &lt;strong&gt;NeoReader&lt;/strong&gt;, is already configured to use the buttons. Most other reader apps &lt;em&gt;can&lt;/em&gt; work with them, but you need to configure them individually.&lt;/p&gt;
&lt;p&gt;Here’s what I’ve found works, using a &lt;a href=&quot;https://hyperborea.org/reviews/products/boox-go7/&quot;&gt;Go 7 Color (Gen II), which I recently bought&lt;/a&gt; to be my new main eBook reader.&lt;/p&gt;
&lt;p&gt;This should also be useful for finding the volume buttons setting when reading books on other Android devices too.&lt;/p&gt;
&lt;h2&gt;System Settings&lt;/h2&gt;
&lt;p&gt;Open the app, then tap the Boox dot menu. The cube with a ring around it will open the system’s customize menu for the app. Open the Others tab, and look for the Customize Buttons setting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Page-turning: Works for some apps, such as Libby.&lt;/li&gt;
&lt;li&gt;Volume: Leave it on here for most e-reader apps, then tell the apps to use the volume buttons for page turning as described below.&lt;/li&gt;
&lt;li&gt;Scrolling: Some apps use this for a slower or smaller scroll amount than Page-turning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Commercial and Library Readers&lt;/h2&gt;
&lt;p&gt;Most of these need the Boox config set to &lt;strong&gt;Volume&lt;/strong&gt;. Then you need to open a book and tap in the center of the screen to get at the menus that have the paging options.&lt;/p&gt;
&lt;h3&gt;Bookshop.org&lt;/h3&gt;
&lt;p&gt;Tap the “…” button, then Visual Settings, then the Advanced tab, and enable “Turn Pages With Volume Buttons.”&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;Related: my &lt;a href=&quot;https://hyperborea.org/reviews/books/bookshop-org/&quot;&gt;review of Bookshop.org and their app&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3&gt;B&amp;amp;N Nook&lt;/h3&gt;
&lt;p&gt;Tap the three vertical dots, then Settings. On that menu, turn on “Enable Volume Buttons.”&lt;/p&gt;
&lt;h3&gt;eBooks.com&lt;/h3&gt;
&lt;p&gt;Tap the gear button. Toward the end of the Settings list, enable “Volume Buttons Turn Pages.”&lt;/p&gt;
&lt;p&gt;Ebooks Reader also pops up a request to rate the app after the first couple of times you use it. Which would be fine except it’s one of those cases where the button color scheme gets mapped to white-on-white, so you can’t read the labels.&lt;/p&gt;
&lt;p&gt;I got around this by using Boox’s dot menu to customize the app’s display and turn on text outlines. It doesn’t seem to affect anything else in the app, just those buttons. But now I can read them.&lt;/p&gt;
&lt;p&gt;For the record, as of the December 2025 version, the order of the buttons is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I Love it!&lt;/li&gt;
&lt;li&gt;Needs Work&lt;/li&gt;
&lt;li&gt;Maybe Later&lt;/li&gt;
&lt;li&gt;No Thanks&lt;/li&gt;
&lt;/ul&gt;
&lt;aside&gt;&lt;p&gt;Related: my &lt;a href=&quot;https://hyperborea.org/reviews/books/ebooks-com/&quot;&gt;review of eBooks.com’s store and app&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;
&lt;h3&gt;Google Play Books&lt;/h3&gt;
&lt;p&gt;Surprisingly, this one doesn’t need you to open a book first. From the main app screen, tap on your account icon in the upper right, then Play Books Settings -&amp;gt; Ebook reading -&amp;gt; “Use volume keys to turn pages.”&lt;/p&gt;
&lt;h3&gt;Kindle&lt;/h3&gt;
&lt;p&gt;Tap on “Aa” for the font display, then go to the More tab and enable “Turn Pages With Volume Controls.”&lt;/p&gt;
&lt;h3&gt;Kobo&lt;/h3&gt;
&lt;p&gt;Tap on “Aa” for the font display. Scroll down past the font settings and enable “Page using volume keys.”&lt;/p&gt;
&lt;aside&gt;&lt;p&gt;Related: my &lt;a href=&quot;https://hyperborea.org/reviews/books/kobo/&quot;&gt;review of Kobo’s shop, the Clara tablet, and their app&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3&gt;Libby&lt;/h3&gt;
&lt;p&gt;Automatically works with the Page-turning option in Boox customizations.&lt;/p&gt;
&lt;h3&gt;Hoopla&lt;/h3&gt;
&lt;p&gt;Automatically works with the Volume option in Boox customizations…but backward from every other app I’ve used.&lt;/p&gt;
&lt;p&gt;Also, you have to enable “Stay active in the background” on the same Customize/Other tab in order to download anything you borrow.&lt;/p&gt;
&lt;h2&gt;Other Apps&lt;/h2&gt;
&lt;h3&gt;Librera&lt;/h3&gt;
&lt;p&gt;Automatically works with the Volume option in Boox customizations if you open a book in “Book mode.” You can turn it off by tapping the gear icon, then un-checking “Navigate with volume buttons.” Librera also has a “Reverse buttons” option, which is something I haven’t found in any of the other apps I’ve used.&lt;/p&gt;
&lt;h3&gt;Nextcloud News&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;https://hyperborea.org/reviews/software/nextcloud-news/&quot;&gt;nice feed reader app&lt;/a&gt; that syncs with a Nextcloud server.&lt;/p&gt;
&lt;p&gt;To use the buttons to scroll up and down within an article, set the Boox config for the app to either Page-turning or Scrolling. They seem to scroll the same amount, but Page-turning moves faster.&lt;/p&gt;
&lt;p&gt;Or, to use the buttons to jump forward and backward &lt;em&gt;between&lt;/em&gt; articles, set it to Volume in the Boox config, and then enable “Navigate with volume buttons” in the app’s Settings list.&lt;/p&gt;
&lt;h3&gt;Wallabag&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;https://hyperborea.org/reviews/software/wallabag/&quot;&gt;great read-it-later app&lt;/a&gt;, like Instapaper. I’ve replaced Pocket with it. Wallabag supports using the buttons to scroll within an article.&lt;/p&gt;
&lt;p&gt;The Boox options for Page-turning and Scrolling both work for moving within an article.&lt;/p&gt;
&lt;p&gt;Or you can set it to Volume, and configure the app itself to use the volume buttons for scrolling. From the main screen’s hamburger menu, open Settings, then UI, then set “Go up and down using the volume buttons.”&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/boox-page-buttons/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Gmail on SeaMonkey</title>
    <link href="https://kvibber.com/tech-tips/seamonkey-gmail/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="computers"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="email"/><category term="gmail"/><category term="seamonkey"/><category term="google"/><category term="mozilla"/>
    <summary>Yes, you can still connect it after the switch to OAuth2. You need to create a placeholder account first, and find the right settings, which Gmail doesn&#39;t seem to tell you anymore.</summary>
    <updated>2025-10-14T19:23:48Z</updated>
    <id>https://kvibber.com/tech-tips/seamonkey-gmail/</id>
    <content type="html">
    &lt;p&gt;As part of checking out the current status of SeaMonkey, I wanted to see if its email client can still connect to Gmail after the move to OAuth2. And it turns out it can!&lt;/p&gt;
&lt;p&gt;I had to create a placeholder account first, then edit the config manually, because SeaMonkey doesn’t come with presets like newer email programs do.&lt;/p&gt;
&lt;p&gt;And then I had to copy over my settings from the much more modern &lt;a href=&quot;https://hyperborea.org/reviews/software/thunderbird/&quot;&gt;Thunderbird&lt;/a&gt;, because &lt;a href=&quot;https://support.google.com/mail/answer/7126229&quot;&gt;Gmail’s documentation&lt;/a&gt; no longer tells you which servers to use, assuming anything that supports OAuth2 is also going to have presets for Google. Once I did that, it popped up a login page when I told it to retrieve new mail.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IMAP pointing to &lt;code&gt;imap.gmail.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SMTP pointing to &lt;code&gt;smtp.gmail.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SSL/TLS as connection security&lt;/li&gt;
&lt;li&gt;OAuth2 as authentication&lt;/li&gt;
&lt;li&gt;Your full email address as the username&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once I had those set up, the first time I told it to retrieve mail for the account it opened up a window with the Google sign-in page.&lt;/p&gt;
&lt;p&gt;(If you’ve disabled cookies, &lt;a href=&quot;https://kvibber.com/tech-tips/thunderbird-gmail-400/&quot;&gt;you’ll need to turn them back on&lt;/a&gt; while you sign in.)&lt;/p&gt;
&lt;p&gt;I expect the same technique should work for other providers using OAuth2 like Outlook and Yahoo. And I’d expect the same settings should work on other email clients that support OAuth2 but don’t autoconfigure Gmail.&lt;/p&gt;
&lt;p&gt;I haven’t found a way to sync address books or calendars with SeaMonkey, though you can theoretically &lt;em&gt;subscribe&lt;/em&gt; to a calendar.&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/seamonkey-gmail/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Unhide the Windows 10 ESU Offer</title>
    <link href="https://kvibber.com/tech-tips/windows10-esu-missing/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="windows"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="microsoft"/><category term="windows-10"/>
    <summary>Windows Update is a bit flaky about making the offer to enroll a Windows 10 system in an extra year of security updates. If it&#39;s not showing the offer, this can make it re-check whether your system qualifies: cmd /c ClipESUConsumer.exe -evaluateEligibility</summary>
    <updated>2025-10-11T05:04:52Z</updated>
    <id>https://kvibber.com/tech-tips/windows10-esu-missing/</id>
    <content type="html">
    &lt;p&gt;After &lt;a href=&quot;https://kvibber.com/tech-tips/windows10-surface-downgrade/&quot;&gt;downgrading the Surface Go 2 back to Windows 10&lt;/a&gt;, I enrolled it in Microsoft’s extended security updates program to keep it current through October 2026. I was surprised to find that I was eligible for the free tier because somewhere along the line I’d synced my settings on this device with my Microsoft account.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.microsoft.com/en-US/windows/extended-security-updates&quot;&gt;Extended Security Updates&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Even better: Each Microsoft account can enroll up to 10 devices at no extra charge, so even if I had to pay the $30, it would still be only $30 for the whole household!&lt;/p&gt;
&lt;h2&gt;Missing&lt;/h2&gt;
&lt;p&gt;I’d been planning to enroll the gaming PC, but the option never seemed to show up when I went to Windows Update. But it showed up when the teenager looked for it on his login, even though his account isn’t eligible.&lt;/p&gt;
&lt;p&gt;Rebooting and messing around with settings didn’t make a difference, so I went looking and found this exchange:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20250823111717/https://learn.microsoft.com/en-us/answers/questions/5512112/my-windows-10-esu-enrollment-message-disappeared-h&quot;&gt;How to get the Windows 10 ESU Enrollment Back&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Running the following in the command prompt under my Windows login fixed the problem, and the next time I opened Windows Update, the offer was visible!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmd /c ClipESUConsumer.exe -evaluateEligibility
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The discussion also mentions some registry settings and service config that may be required under some circumstances, or may only have been required back in August, before the ESU was rolled out broadly to consumers. For me, in October, just running the ClipESUConsumer command did the trick.&lt;/p&gt;
&lt;h2&gt;What’s Going On?&lt;/h2&gt;
&lt;p&gt;It’s not clear, but this seems likely:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Windows Update doesn’t check for eligibility in ESU every time you launch it. Or when you log in. Or when you power on the machine. I’m not sure how often it checks, but it’s apparently not often enough.&lt;/li&gt;
&lt;li&gt;It checks for the machine’s eligibility &lt;em&gt;per user&lt;/em&gt;. That’s the only explanation for why it made the offer on an account that couldn’t accept it, but didn’t make the offer on an account that could. Well, the only &lt;em&gt;good&lt;/em&gt; explanation, anyway.&lt;/li&gt;
&lt;li&gt;It doesn’t check whether the user is eligible, leaving that for when you try to enroll.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In any case, now the gaming PC has another year of security updates for Windows, and we don’t have to upgrade it to Windows 11 yet!&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/windows10-esu-missing/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>Downgrading a Microsoft Surface Device to Windows 10</title>
    <link href="https://kvibber.com/tech-tips/windows10-surface-downgrade/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="windows"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="microsoft"/><category term="surface"/><category term="tablet"/><category term="drivers"/><category term="windows-10"/><category term="windows-11"/>
    <summary>You can reinstall Windows on a Surface tablet or laptop using a hardware-specific recovery image and a USB drive. Microsoft will want you to log in and provide the serial number of the device you want to reinstall.</summary>
    <updated>2025-10-11T01:09:02Z</updated>
    <id>https://kvibber.com/tech-tips/windows10-surface-downgrade/</id>
    <content type="html">
    &lt;p&gt;&lt;a href=&quot;https://hyperborea.org/reviews/products/surfacego2/&quot;&gt;The Surface Go 2 is a surprisingly good Windows 10 tablet!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s also a frustratingly slow Windows 11 tablet. I got the go-ahead from the rest of the household to reinstall Windows 10 on it.&lt;/p&gt;
&lt;p&gt;My big concern was that the Surface Go 2 is a very specific hardware device, and I wasn’t sure just booting to the most recent Windows 10 installation image would find all the drivers, especially the pen support. So I did a little digging, and found that Microsoft provides recovery images for the Surface line (and not just the tablets and laptops), much like Android manufacturers (sometimes) provide images to reset their devices to a known working version.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://support.microsoft.com/en-us/surface-recovery-image&quot;&gt;Surface Recovery Images&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Setting Up for Setup&lt;/h2&gt;
&lt;p&gt;You have to log in with a Microsoft account, and you have to provide the serial number of the device you want to reinstall. At the moment, you can still download an installer for either Windows 10 or Windows 11 (at least for some Surface tablets, including the Go 2). I wouldn’t count on them keeping the older images available after (checks calendar) &lt;strong&gt;next week, so move fast&lt;/strong&gt; and grab a copy just in case you need it later on.&lt;/p&gt;
&lt;p&gt;It’s a little weird: You don’t download a bootable image, you download a zip file. Then you use some Windows 10/11 box to create a bootable USB recovery drive, and then copy the &lt;em&gt;contents&lt;/em&gt; of the zip file over, replacing whatever recovery system your own box set up.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://support.microsoft.com/en-us/surface/creating-and-using-a-usb-recovery-drive-for-surface-677852e2-ed34-45cb-40ef-398fc7d62c07&quot;&gt;Creating and using a USB recovery drive for Surface&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then you power the tablet on while holding down the down volume button (again, similar to booting an Android device to its recovery image), and go through the options until you find “Recover from a drive,” and reinstall Windows from there. (It’ll also ask for a Bitlocker recovery key to unlock the drive, but you’re going to wipe it anyway, so you can just skip unlocking it.)&lt;/p&gt;
&lt;p&gt;And then you wait.&lt;/p&gt;
&lt;p&gt;And then you log in, and it’ll be really slow while it downloads however many years of Windows 10 updates since the image you reverted it to, and you wait for those to install, and then it’ll be fast again!&lt;/p&gt;
&lt;h2&gt;Extension&lt;/h2&gt;
&lt;p&gt;If you &lt;em&gt;have&lt;/em&gt; decided to downgrade, you may want to look into the extra year of security updates through October 2026.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.microsoft.com/en-US/windows/end-of-support?r=1#FAQ3&quot;&gt;Windows 10 Extended Security Updates (ESU)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s a one-time $30 purchase that you can use with up to 10 devices. I’ve enrolled three: the Surface, the gaming PC, and the Windows partition on my dual-boot desktop. And there are ways to qualify for the program for free, like if you’ve ever backed up your settings to the cloud. Sometimes Windows Update forgets to show you the offer, in which case you might be able to &lt;a href=&quot;https://kvibber.com/tech-tips/windows10-esu-missing/&quot;&gt;get it to re-check eligibility&lt;/a&gt;.&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/windows10-surface-downgrade/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
  
  
  
  <entry>
    <title>GNOME/Wayland Fails to Log In After Installing XFCE (Solved)</title>
    <link href="https://kvibber.com/tech-tips/wayland-gnome-auth-fail/"/>
    <author>
      <name>Kelson Vibber</name>
      <email>techtips@kvibber.com</email>
      <uri>https://kvibber.com</uri>
    </author>
    <category term="linux"/>
    <category term="howto"/>
    <category term="techtips"/>
    <category term="gnome"/><category term="wayland"/><category term="xfce"/><category term="lxqt"/>
    <summary>The most ridiculous Linux bug I&#39;ve encountered in ages: Installing XFCE changed a mouse cursor setting for GNOME that caused the login screen to crash when trying to log into GNOME/Wayland.</summary>
    <updated>2025-07-21T04:12:42Z</updated>
    <id>https://kvibber.com/tech-tips/wayland-gnome-auth-fail/</id>
    <content type="html">
    &lt;p&gt;OK, this has got to be the most ridiculous Linux bug I’ve encountered in a &lt;em&gt;long&lt;/em&gt; time.&lt;/p&gt;
&lt;p&gt;Installing XFCE/X11 on my Fedora system made it impossible to log into GNOME/Wayland. I finally tracked down what was causing it through an &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?id=306641&quot;&gt;Arch forum thread&lt;/a&gt; pointing to a &lt;a href=&quot;https://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg2038806.html&quot;&gt;Debian bug report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And the problem was that &lt;em&gt;XFCE set the GNOME mouse cursor size to zero&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Solution:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gsettings reset org.gnome.desktop.interface cursor-size
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Wait, What Is All This?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/X_Window_System&quot;&gt;&lt;strong&gt;X11&lt;/strong&gt; is an older display system&lt;/a&gt; designed for old-style computer lab scenarios with multiple terminals running software from a server, that’s been tweaked and layered and otherwise finagled into mostly working on personal desktops.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xorg&lt;/strong&gt; is the project that most Linux systems use for their X11 layer.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Wayland_(protocol)&quot;&gt;&lt;strong&gt;Wayland&lt;/strong&gt; is a newer display system&lt;/a&gt; designed for personal computers, but it’s taken years to add back some of the features people relied on. Older programs that are designed only for X11 can run through a compatibility layer called &lt;strong&gt;XWayland&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.gnome.org&quot;&gt;GNOME&lt;/a&gt;, &lt;a href=&quot;https://www.xfce.org&quot;&gt;XFCE&lt;/a&gt;, and &lt;a href=&quot;https://lxqt-project.org&quot;&gt;LXQt&lt;/a&gt;&lt;/strong&gt; are desktop environments that handle windowing, docks, menus and a set of standard tools for things like file management.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Why Wayland? Why X11?&lt;/h2&gt;
&lt;p&gt;As of mid-2025, anything that runs directly on Wayland works &lt;em&gt;better&lt;/em&gt; on my desktop than it does on an X session, and most programs that use the XWayland compatibility layer work fine. Plus &lt;a href=&quot;https://waydro.id&quot;&gt;Waydroid&lt;/a&gt; is useful for running the occasional Android app on my Linux desktop.&lt;/p&gt;
&lt;p&gt;But there are a few games that still have trouble. &lt;a href=&quot;https://hyperborea.org/reviews/games/no-mans-sky/&quot;&gt;&lt;em&gt;No Man’s Sky&lt;/em&gt;&lt;/a&gt;, for instance, usually starts out OK but slows to an unplayable crawl after a few minutes when I run it on Wayland, but not when I run it on X11. (I assume it’s a &lt;a href=&quot;https://notes.kvibber.com/@kelson/statuses/01J3JV12R3ACRJRY9SW5YBTZPQ&quot;&gt;lingering Wayland/NVidia bug&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;So I run GNOME/Wayland most of the time, but switch over to GNOME/X11 for some games. Which would be fine except that &lt;a href=&quot;https://blogs.gnome.org/alatiera/2025/06/23/x11-session-removal-faq/&quot;&gt;GNOME is dropping X11 support soon&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;OK, So What Happened?&lt;/h2&gt;
&lt;p&gt;I installed XFCE, which is &lt;a href=&quot;https://linuxiac.com/xfce-4-20-will-keep-x11-support/&quot;&gt;keeping their X11 support&lt;/a&gt;. I logged in. I ran Steam. I logged back out and tried to log into GNOME/Wayland again…&lt;/p&gt;
&lt;p&gt;…and got sent back to the login screen with an “authentication error” and a password field that wouldn’t accept input. I had to switch to a text console and restart GDM (the program that handles the login screen).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl restart gdm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could log into GNOME/X11. I could log into XFCE. I reinstalled LXQt (which I use on a low-spec portable and on VMs) and was able to log into it with both Wayland or X11, but GNOME applications wouldn’t run on the Wayland session. But even after a reboot, any attempt to log into GNOME/Wayland locked up the login screen the same way.&lt;/p&gt;
&lt;p&gt;A couple of hours and &lt;a href=&quot;https://publicdomainreview.org/collection/visualizing-migraines/&quot;&gt;a literal migraine&lt;/a&gt; later, I found the Arch thread where someone had &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?id=306641&quot;&gt;exactly the same experience&lt;/a&gt;: They installed XFCE, after which launching GNOME/Wayland would always lock up the login screen. And it was eventually traced to that bug with the cursor size.&lt;/p&gt;
&lt;p&gt;I had to look up the syntax for gsettings (which I found on &lt;a href=&quot;https://forums.linuxmint.com/viewtopic.php?t=305934&quot;&gt;a Mint forum thread&lt;/a&gt;), and confirmed that yes, it was set to zero:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gsettings get org.gnome.desktop.interface cursor-size

0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and reset it to the default:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gsettings reset org.gnome.desktop.interface cursor-size
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, surprise, GNOME/Wayland worked again!&lt;/p&gt;
&lt;h2&gt;Unanswered Questions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Why is XFCE changing the mouse cursor size for GNOME?&lt;/li&gt;
&lt;li&gt;Why is it setting it to &lt;em&gt;zero&lt;/em&gt;???&lt;/li&gt;
&lt;li&gt;Why does it crash GNOME under Wayland, but not under X11?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Update 1: Jeff Fortin found &lt;a href=&quot;https://gitlab.gnome.org/GNOME/mutter/-/issues/3933&quot;&gt;the GNOME bug report for the crash&lt;/a&gt; and reminded me I should report the cursor setting to XFCE.&lt;/p&gt;
&lt;p&gt;Update 2: Here’s &lt;a href=&quot;https://gitlab.xfce.org/xfce/xfce4-settings/-/issues/610&quot;&gt;the XFCE bug report for the cursor setting&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Update 3: Three months later, even with other people running into the same problem and commenting on the bug report, the XFCE maintainer is still saying they shouldn’t have to change it because…Linux users shouldn’t be installing multiple desktops on the same computer???&lt;/p&gt;
&lt;p&gt;Sure, &#39;cause &lt;a href=&quot;https://distrowatch.com&quot;&gt;&lt;em&gt;no one ever does that&lt;/em&gt;&lt;/a&gt;. Serious &lt;a href=&quot;https://www.wired.com/2010/06/iphone-4-holding-it-wrong/&quot;&gt;“you’re holding it wrong”&lt;/a&gt; energy.&lt;/p&gt;
&lt;h2&gt;Amusement&lt;/h2&gt;
&lt;p&gt;I had to teach the spell checker some new words. Some of the suggestions it had:&lt;/p&gt;
&lt;p&gt;Wayland -&amp;gt; Waylaid&lt;br&gt;
XFCE -&amp;gt; FACE&lt;br&gt;
systemctl -&amp;gt; systemic&lt;/p&gt;
&lt;footer&gt;This post by &lt;a class=&quot;p-author h-card&quot; rel=&quot;author&quot; href=&quot;https://kvibber.com&quot;&gt;Kelson Vibber&lt;/a&gt; originally appeared &lt;a class=&quot;u-url&quot; href=&quot;https://kvibber.com/tech-tips/wayland-gnome-auth-fail/&quot;&gt;on KV Tech Tips&lt;/a&gt;&lt;/footer&gt;</content>
  </entry>
</feed>
