<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><![CDATA[The Education of James Endres Howell]]></title>
<description><![CDATA[The Education of James Endres Howell]]></description>
<link>https://jamesendreshowell.com/</link>
<atom:link href="https://jamesendreshowell.com/rss.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Wed, 15 Apr 2026 20:32:25 -0400</lastBuildDate>
<item>
  <title><![CDATA[Embedding a Mastodon thread as comments to a blog post]]></title>
  <description><![CDATA[
<div class="post-date">2026 Apr 15</div><p>
I wrote <code>org-static-blog-emfed</code>, <a href="https://codeberg.org/jamesendreshowell/org-static-blog-emfed">a little Emacs package that extends <code>org-static-blog</code> with the ability to embed a Mastodon thread in a blog post to serve as comments</a>. The root of the Mastodon thread also serves as an announcement of the blog post to your followers. It&rsquo;s based on Adrian Sampson&rsquo;s <a href="https://github.com/sampsyo/emfed">Emfed,</a> and of course Bastian Bechtold&rsquo;s <a href="https://github.com/bastibe/org-static-blog"><code>org-static-blog</code></a>.
</p>

<p>
I had shared it before, but alas, after changing Mastodon instances the comments from old posts were lost, so I disabled them on this blog. Just over the past few days I&rsquo;ve found time to get it all working again.
</p>

<p>
It also seems, at least in <a href="https://fediscience.org/tags/Emacs">#Emacs on Mastodon</a>, that <code>org-static-blog</code> has gained in popularity recently. 
</p>

<p>
Prompted as I was to make a few improvements, I thought I would update the README and share it again. Hope it&rsquo;s useful for someone!
</p>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-emacs.html">emacs</a> <a href="https://jamesendreshowell.com/tag-blog.html">blog</a> <a href="https://jamesendreshowell.com/tag-org-mode.html">org-mode</a> </div></div>
]]></description>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[blog]]></category>
  <category><![CDATA[org-mode]]></category>
  <link>https://jamesendreshowell.com/2026-04-15-embedding-a-mastodon-thread-as-comments-to-a-blog-post.html</link>
  <guid>https://jamesendreshowell.com/2026-04-15-embedding-a-mastodon-thread-as-comments-to-a-blog-post.html</guid>
  <pubDate>Wed, 15 Apr 2026 18:17:00 -0400</pubDate>
</item>
<item>
  <title><![CDATA[My first advice! (in Emacs Lisp)]]></title>
  <description><![CDATA[
<div class="post-date">2026 Apr 04</div><p>
It was really fun to learn about 
<a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html"><i>advising</i> Lisp functions</a>
to extend functionality in Emacs. My first use case was to run a custom function every time a certain function in
<a href="https://bastibe.de/about.html">Bastian Bechtold</a>&rsquo;s
<a href="https://github.com/bastibe/org-static-blog"><code>org-static-blog</code></a> is called. Of course, I could customize that function directly in my own fork, but Lisp advice allows you to modify functions without clobbering them directly. This approach has aesthetic and practical advantages.
</p>

<p>
But I&rsquo;ve struggled to understand the concepts and implementation of advice. Today I 
<a href="https://fediscience.org/@jameshowell/116348033254934806">posted to Mastodon</a>
about how excited I was to get my first working use, and 
<a href="https://fediscience.org/@pkal@social.sdfeu.org">Philip</a> asked me to share the code.
</p>

<p>
My problem was specifying HTML boilerplate that <code>org-static-blog</code> puts in each post when it publishes all the static files, using string variables like <code>org-static-blog-page-header</code>. These strings are complex enough that I put them in their own files, like these lines in the <code>#header.html</code> file that specifies the page metadata:
</p>

<div class="org-src-container">
<pre class="src src-html">&lt;<span style="color: #721045;">script</span> <span style="color: #005e8b;">type</span>=<span style="color: #3548cf;">"module"</span> <span style="color: #005e8b;">src</span>=<span style="color: #3548cf;">"https://esm.sh/emfed@"</span>&gt;&lt;/<span style="color: #721045;">script</span>&gt;
&lt;<span style="color: #721045;">meta</span> <span style="color: #005e8b;">name</span>=<span style="color: #3548cf;">"author"</span> <span style="color: #005e8b;">content</span>=<span style="color: #3548cf;">"James Endres Howell"</span>&gt;
&lt;<span style="color: #721045;">meta</span> <span style="color: #005e8b;">name</span>=<span style="color: #3548cf;">"referrer"</span> <span style="color: #005e8b;">content</span>=<span style="color: #3548cf;">"no-referrer"</span>&gt;
&lt;<span style="color: #721045;">link</span> <span style="color: #005e8b;">href</span>=<span style="color: #3548cf;">"static/style.css"</span> <span style="color: #005e8b;">rel</span>=<span style="color: #3548cf;">"stylesheet"</span> <span style="color: #005e8b;">type</span>=<span style="color: #3548cf;">"text/css"</span> /&gt;
&lt;<span style="color: #721045;">meta</span> <span style="color: #005e8b;">name</span>=<span style="color: #3548cf;">"fediverse:creator"</span> <span style="color: #005e8b;">content</span>=<span style="color: #3548cf;">"@jameshowell@fediscience.org"</span>&gt;
&lt;<span style="color: #721045;">meta</span> <span style="color: #005e8b;">property</span>=<span style="color: #3548cf;">"og:image"</span> 
      <span style="color: #005e8b;">content</span>=<span style="color: #3548cf;">"https://jamesendreshowell.com/static/education-of-james-endres-howell.png"</span>&gt;
</pre>
</div>

<p>
First, Stack Exchange and I solved the problem of reading a file into a string. (?! How is this not a native function!? Maybe I missed something obvious.)
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span style="color: #531ab6;">defun</span> <span style="color: #721045;">jeh/file-to-string</span> (file)
  <span style="color: #2a5045;">"Return a string that is the contents of FILE."</span>
  (<span style="color: #531ab6;">with-temp-buffer</span>
    (insert-file-contents file)
    (buffer-string)))
</pre>
</div>

<p>
And then, for example:
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span style="color: #531ab6;">setq</span> org-static-blog-page-header
      (jeh/file-to-string 
       (expand-file-name <span style="color: #3548cf;">"#header.html"</span> org-static-blog-template-blocks-directory)))
</pre>
</div>

<p>
The unscratched itch was that every time I edit one of these files, <i>I always, <b>but always</b>, forget to update the appropriate variable</i> with the contents of the file! And so publishing doesn&rsquo;t reflect the changes, and I get confused, and then I remember&#x2026;.
</p>

<p>
Here is the solution:
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">
(<span style="color: #531ab6;">defun</span> <span style="color: #721045;">jeh/org-static-blog-read-templates</span> (<span style="color: #005f5f;">&amp;rest</span> ignore)
  <span style="color: #2a5045;">"Set org-static-blog-page -header, -preamble, -postamble variables
by reading files from `</span><span style="color: #0000b0;">org-static-blog-template-blocks-directory</span><span style="color: #2a5045;">'."</span>
  (<span style="color: #531ab6;">setq</span> org-static-blog-page-header             <span style="color: #595959;">;;; </span><span style="color: #595959;">HTML to put in the &lt;head&gt; of each page.
</span>        (jeh/file-to-string 
         (expand-file-name <span style="color: #3548cf;">"#header.html"</span> org-static-blog-template-blocks-directory)))
  (<span style="color: #531ab6;">setq</span> org-static-blog-page-preamble           <span style="color: #595959;">;;; </span><span style="color: #595959;">HTML to put before the content of each page.
</span>        (jeh/file-to-string 
         (expand-file-name <span style="color: #3548cf;">"#preamble.html"</span> org-static-blog-template-blocks-directory)))
  (<span style="color: #531ab6;">setq</span> org-static-blog-page-postamble          <span style="color: #595959;">;;; </span><span style="color: #595959;">HTML to put after the content of each page.
</span>        (format (jeh/file-to-string 
                 (expand-file-name <span style="color: #3548cf;">"#postamble.html"</span> org-static-blog-template-blocks-directory))
                (number-to-string emacs-major-version)
                (number-to-string emacs-minor-version)
                org-version)))

<span style="color: #595959;">;;; </span><span style="color: #595959;">Re-read the template files before publishing,
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">so changes will be included in output.
</span>(advice-add #'org-static-blog-publish <span style="color: #8f0075;">:before</span> #'jeh/org-static-blog-read-templates)
</pre>
</div>

<p>
The function <code>jeh/org-static-blog-read-templates</code> sets the variables
<code>org-static-blog-page-header</code>,
<code>org-static-blog-page-preamble</code>, and
<code>org-static-blog-page-postamble</code> to the contents of the appropriate files. Making that function a hook to the function which generates all the static pages, <code>org-static-blog-publish</code>, solves my problem. But there is no hook for it! I had a suspicion that <code>add-advice</code> could give me the same result, and&#x2014;I hope you&rsquo;re sitting down&#x2014;I
<a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advice-Combinators.html">read the fine manual</a>
and learned that the syntax of the last line accomplishes that very thing.
</p>

<p>
Of course, <code>advice-add</code> (and related functions) can do much more! Maybe as I learn I will be able to customize functions from other packages without just banging on a local fork.
</p>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-emacs.html">emacs</a> </div></div>
]]></description>
  <category><![CDATA[emacs]]></category>
  <link>https://jamesendreshowell.com/2026-04-04-my-first-advice-in-emacs-lisp.html</link>
  <guid>https://jamesendreshowell.com/2026-04-04-my-first-advice-in-emacs-lisp.html</guid>
  <pubDate>Sat, 04 Apr 2026 18:41:00 -0400</pubDate>
</item>
<item>
  <title><![CDATA[Replacing Cinnamon with GNOME on Linux Mint Debian Edition]]></title>
  <description><![CDATA[
<div class="post-date">2026 Mar 10</div><p>
I loyally enjoy running <a href="https://www.debian.org/">Debian Stable</a>. I am with less enthusiasm accustomed to <a href="https://www.gnome.org/">GNOME</a>,  after years of habit and customizations on which I have come to rely. But Debian has some disadvantages: for me, it was that (apparently) GRUB was not always configured correctly after installation to a random laptop. Meanwhile Linux Mint (inlcuding LMDE) installs are always solid. And I am too thick to troubleshoot GRUB. I found that I can have the best of both worlds.
</p>

<p>
<a href="https://www.linuxmint.com/">Linux Mint</a> is a popular and highly-recommended Linux distribution based on Ubuntu. I avoid Ubuntu, although Linux Mint overcomes many of my objections (by removing snaps and other Canonical transgressions). But there is also a <a href="https://www.linuxmint.com/download_lmde.php">Linux Mint Debian Edition</a> (LMDE) in which Linux Mint user affordances, including its <a href="https://en.wikipedia.org/wiki/Cinnamon_(desktop_environment)">Cinnamon</a> desktop environment, are built atop Debian instead. (For the record, I install Linux Mint on machines that I give to people who want to try Linux. Everything just works, reliably, and Cinnamon is a great entry point for Windows refugees, with a nice familiar look and feel.)
</p>

<p>
To my surprise, it turns out that it is possible to completely remove Cinnamon and its dependencies from LMDE and replace it with GNOME. The resulting experience is very similar to a Debian GNOME install, with the following differences (that I take to be advantages):
</p>

<ul class="org-ul">
<li>a new install boots on more of the machines I have lying around</li>

<li>the repositories curated by the Ubuntu and Linux Mint folks have newer versions (e.g. of GNOME and Emacs) than the Debian Stable repositories.</li>
</ul>
<div id="outline-container-orgcb50720" class="outline-2">
<h2 id="orgcb50720">Install and update</h2>
<div class="outline-text-2" id="text-orgcb50720">
<p>
Start with a <a href="https://www.linuxmint.com/edition.php?id=325">fresh install of Linux Mint Debian Edition (LMDE 7 &ldquo;Gigi&rdquo;)</a> based on Debian 13 &ldquo;Trixie.&rdquo;
</p>

<p>
Open a terminal and bring everything up to date. This could take awhile, but it cannot be skipped (I checked). I didn&rsquo;t bother to try to determine which dependencies are important.
</p>

<div class="org-src-container">
<pre class="src src-sh">apt update
apt upgrade
reboot
</pre>
</div>
</div>
</div>
<div id="outline-container-org03d6548" class="outline-2">
<h2 id="org03d6548">Install GNOME with <code>tasksel</code>.</h2>
<div class="outline-text-2" id="text-org03d6548">
<p>
The most reliable way to install GNOME is via <code>tasksel</code>.
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo apt install tasksel
sudo tasksel
</pre>
</div>

<p>
From the <code>tasksel</code> menu:
</p>

<pre class="example" id="org8b66cf5">
Choose software to install:

   [*] Debian desktop environment
   [*] ... GNOME
   [ ] ... Xfce
   [ ] ... GNOME Flashback
   [ ] ... KDE Plasma
   [ ] ... Cinnamon
   [ ] ... MATE
   [ ] ... LXDE
   [ ] ... LXQt

</pre>

<p>
select both <code>Debian desktop environment</code> and <code>GNOME</code>.
</p>

<p>
Another menu will appear for choosing a &ldquo;display&rdquo; (login) manager. I prefer <code>gdm3</code> because it follows GNOME customization settings.
</p>

<pre class="example" id="orgc7c807b">
Default display manager:

         gdm3
         lightdm
</pre>


<p>
<b>Reboot again.</b> Note that login is now via <code>gdm3</code> and that your default login is now into GNOME.
</p>
</div>
</div>
<div id="outline-container-org81cedad" class="outline-2">
<h2 id="org81cedad">Remove Cinnamon packages</h2>
<div class="outline-text-2" id="text-org81cedad">
<p>
You certainly could stop here and keep Cinnamon installed. You could also leave all the Linux Mint default Cinnamon apps installed. But I don&rsquo;t want any of this stuff. The <code>mint*</code> packages are cosmetic user-interface stuff that customizes Cinnamon.
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo apt autoremove --purge cinnamon* mint*
</pre>
</div>

<p>
After that last step, log out and log in again. Note: some icons might be missing in e.g. Nautilus windows; use <a href="https://github.com/GNOME/gnome-tweaks">GNOME Tweaks</a> (<code>sudo apt install gnome-tweaks</code>) 
Appearance → Styles → Icons → Adwaita (default) to restore the GNOME defaults.
</p>

<p>
I was surprised that I could remove all of the <code>cinnamon*</code> and <code>mint*</code> packages from LMDE without breaking anything. And then to get what appears to be a nice stock Debian/GNOME environment, with the benefits of Linux Mint.
</p>
</div>
</div>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-debian.html">debian</a> </div></div>
]]></description>
  <category><![CDATA[debian]]></category>
  <link>https://jamesendreshowell.com/2026-03-10-replacing-cinnamon-with-gnome-on-linux-mint-debian-edition.html</link>
  <guid>https://jamesendreshowell.com/2026-03-10-replacing-cinnamon-with-gnome-on-linux-mint-debian-edition.html</guid>
  <pubDate>Tue, 10 Mar 2026 12:34:00 -0400</pubDate>
</item>
<item>
  <title><![CDATA[What Black History Month means to me]]></title>
  <description><![CDATA[
<div class="post-date">2026 Feb 25</div><p>
I was in high school during the 1980s. In a little rural town in Ohio where casual racism was perfectly commonplace. Black History Month had been around for 15 years, and people already loved to complain about &ldquo;Isn&rsquo;t EVERY month Black History Month?&rdquo;
</p>

<p>
Politicians were fighting over the idea of a national holiday to honor Martin Luther King. There were two positions: &ldquo;Of course! How can we not?&rdquo; and &ldquo;IMPOSSIBLE! UNNECESSARY! WE CAN&rsquo;T JUST HAND OUT NATIONAL HOLIDAYS LIKE KLEENEX RARRRR&rdquo;
</p>

<p>
It would be an exaggeration to say I had never <i>met</i> a black person, but I sure could not have said that I <i>knew</i> any black people. My high school had two or three black kids out of six or seven hundred? Two Jewish families, one kept it secret. One Asian family? Kids who were not white <i>stuck out.</i>
</p>

<p>
I was a sensitive kid. I hated, I hated, I hated the racism, the anti-semitism, the misogyny we were all marinated in. I was lucky: I had an exceptional US history teacher, Mr. Jim Fuller. He deserves a shoutout. I <i>loved</i> history class. He showed us enough history for us to see that a lot of black history had been left out. I was able to see that black history is American history, and I was angry to see it left out. I felt that it was an injustice <i>to us</i>, to the <i>white kids</i>, to exclude black history from our shared history.
</p>

<p>
I understood that the resistance to MLK Day and Black History Month represented the desire to make black people invisible. But I thought it was just that they wanted to erase black history in order to keep us from feeling sympathy to black people, to keep us from being inflamed with outrage over the long litany of injustices against our fellow citizens. Against the injustices of slavery, of a half-assed Reconstruction, of Jim Crow, of a half-assed, foot-dragging response to the Civil Rights Movement. <i>I thought it was just a racist rejection of empathy.</i>
</p>

<p>
But after high school, as I continued to study history, as I continued to read, as I found black authors to read, I realized that it was much more. It was not just a rejection of empathy. I realized that the racist establishment&rsquo;s greatest fear was not that white high school kids would empathize with black Americans. I realized that the racist establishment&rsquo;s greatest fear is that <i>white high school kids will find black heroes to admire.</i> Their greatest fear is that white kids will <i>identify with black American heroes.</i>
</p>

<p>
I realized that they wanted to erase black history, not to keep me from empathizing with black Americans. I realized they wanted to erase black history so I would not find
bell hooks, or
Angela Davis, or
Kevin Alexander Gray, or
Cornell West, or
Amiri Baraka, or
Frederick Douglass, or
James Baldwin, or
Paul Robeson. <i>To keep me from aspiring to be like them.</i> So that I would not <i>aspire</i> to reach down deep and find the courage to think and write and speak out as incisively and as honestly and most of all as <i>bravely</i> as my black heroes.
</p>

<p>
That&rsquo;s what Black History Month means to me.
</p>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-politics.html">politics</a> <a href="https://jamesendreshowell.com/tag-teaching.html">teaching</a> </div></div>
]]></description>
  <category><![CDATA[politics]]></category>
  <category><![CDATA[teaching]]></category>
  <link>https://jamesendreshowell.com/2026-02-25-what-black-history-month-means-to-me.html</link>
  <guid>https://jamesendreshowell.com/2026-02-25-what-black-history-month-means-to-me.html</guid>
  <pubDate>Wed, 25 Feb 2026 11:11:00 -0500</pubDate>
</item>
<item>
  <title><![CDATA[Custom sorting of mu4e headers]]></title>
  <description><![CDATA[
<div class="post-date">2026 Jan 08</div><p>
I love <code>mu4e</code> for dealing with email under Emacs. It&rsquo;s a great package itself, but of course the killer feature is that it&rsquo;s Emacs, and with a little Emacs Lisp you can make it do email how <i>you</i> want to do email. I mean I know <i>you don&rsquo;t want to do email,</i> but still.
</p>
<div id="outline-container-org03b702d" class="outline-2">
<h2 id="org03b702d">My email workflow</h2>
<div class="outline-text-2" id="text-org03b702d">
<p>
I use Fastmail, which I can recommend overall. I have only a few top-level folders:
</p>

<pre class="example" id="org550d004">
Inbox
work
personal
Spam
Drafts
Sent
Archived
Trash
</pre>

<p>
I have quite a few filters set up so that everything not to my work email (and a few other criteria) go into <code>personal</code>, and work mailing lists and other low-priority stuff go into <code>work</code>. Meanwhile lots of garbage gets ruthlessly sent straight to <code>Trash</code>. And Fastmail is quite good (both <a href="https://en.wikipedia.org/wiki/Type_I_and_type_II_errors">Type I and Type II</a> good) at detecting <code>Spam</code>. Of course every outgoing message goes to <code>Sent</code>.
</p>

<p>
The <i>one good thing</i> about the years I spent in Gmail was acquiring the habit that emails are either not done (in the GTD sense) until they are put into <code>Archive</code>, or they are filed irreversibly into <code>Archive</code> at which time they are done done done. Every email has a binary state: not yet in <code>Archive</code> and pending action (including a mere reply), or put into <code>Archive</code>. In short, <code>Inbox</code> is enriched for high-priority messages because lower-priority messages go to <code>work</code> and <code>personal</code>. From each of those three, I step through messages and file them <code>Archive</code> after they are done.
</p>

<p>
This workflow, refined over two decades, works very well for me.
</p>

<p>
Finally, I have two virtual folders, <code>mu4e</code> searches that are saved as &rsquo;bookmarks,&rsquo; that I call <code>Unread</code> and <code>Evacuate</code>. The former shows me everything unread in <code>Inbox</code>, <code>personal</code>, and <code>work</code>, for rare times when I prefer to process them all at once. The latter shows me everything in those folders that is already read, but not yet sent to <code>Archive</code>. Pending action, in other words, waiting to be <i>evacuated</i> to <code>Archive</code>.
</p>

<p>
Thus, many times a day I can browse through <code>Unread</code> emails, quickly in <code>mu4e</code> or even on the Fastmail app on my phone, and triage away low-priority messages, immediately deal with urgent messages, and know that the ones I ignore for the time being are waiting for me to <code>Evacuate</code> later.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #595959;">;;; </span><span style="color: #595959;">"Unread" bookmark is everything not yet marked read
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">except messages already filtered directly to Trash
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">or automatically marked as Spam.
</span>(<span style="color: #531ab6;">defcustom</span> <span style="color: #005e8b;">jeh/mu4e-bookmark-unread</span> <span style="color: #3548cf;">"flag:unread AND NOT flag:trashed AND NOT maildir:/Spam"</span>
  <span style="color: #2a5045;">"String for mu4e search of '</span><span style="color: #0000b0;">Unread</span><span style="color: #2a5045;">' messages."</span>)

<span style="color: #595959;">;;; </span><span style="color: #595959;">"Evacuate" bookmark is kinda the converse of unread:
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">message that have been marked as read, but not yet
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">refiled into Archive. Pending action, in other words.
</span>(<span style="color: #531ab6;">defcustom</span> <span style="color: #005e8b;">jeh/mu4e-bookmark-evacuate</span>
      (concat <span style="color: #3548cf;">"flag:seen and "</span>
              <span style="color: #3548cf;">"not ("</span>
                   <span style="color: #3548cf;">" flag:trashed"</span>
                   <span style="color: #3548cf;">" or maildir:/Sent"</span>
                   <span style="color: #3548cf;">" or maildir:/Archive"</span>
                   <span style="color: #3548cf;">" or maildir:/Scheduled"</span>
                   <span style="color: #3548cf;">" or maildir:/Drafts"</span>
                   <span style="color: #3548cf;">" or maildir:/Trash"</span>
                   <span style="color: #3548cf;">" or maildir:/Spam"</span>
              <span style="color: #3548cf;">")"</span>)
      <span style="color: #2a5045;">"String for mu4e search for '</span><span style="color: #0000b0;">Evacuate</span><span style="color: #2a5045;">' or pending
messages, read but not yet refiled in Archive."</span>)

(<span style="color: #531ab6;">setq</span> mu4e-bookmarks
      `((<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Inbox"</span> <span style="color: #8f0075;">:key</span> ?i <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/Inbox"</span>)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Work"</span> <span style="color: #8f0075;">:key</span> ?w <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/work"</span>)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Personal"</span> <span style="color: #8f0075;">:key</span> ?p <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/personal"</span>) 
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Drafts"</span> <span style="color: #8f0075;">:key</span> ?d <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/Drafts"</span>)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Spam"</span> <span style="color: #8f0075;">:key</span> ?s <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/Spam"</span>)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Trash"</span> <span style="color: #8f0075;">:key</span> ?t <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/Trash"</span>)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Sent"</span> <span style="color: #8f0075;">:key</span> ?n <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/Sent"</span>)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Archive"</span> <span style="color: #8f0075;">:key</span> ?a <span style="color: #8f0075;">:query</span> <span style="color: #3548cf;">"maildir:/Archive"</span>)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Evacuate"</span> <span style="color: #8f0075;">:key</span> ?e <span style="color: #8f0075;">:query</span> ,jeh/mu4e-bookmark-evacuate)
        (<span style="color: #8f0075;">:name</span> <span style="color: #3548cf;">"Unread"</span> <span style="color: #8f0075;">:key</span> ?u <span style="color: #8f0075;">:query</span> ,jeh/mu4e-bookmark-unread)))
</pre>
</div>

<p>
I&rsquo;ve had this working nicely in <code>mu4e</code> for a couple years.
</p>
</div>
</div>
<div id="outline-container-org44cb966" class="outline-2">
<h2 id="org44cb966">Custom sorting depending on &ldquo;folder&rdquo; (or search)</h2>
<div class="outline-text-2" id="text-org44cb966">
<p>
But something annoyed me!
</p>

<p>
<code>Archive</code> and <code>Sent</code> have tens of thousands of messages, while all the other folders usually have less than a dozen. (Honest to god, this system keeps me at a calming steady state of <a href="https://en.wikipedia.org/wiki/Merlin_Mann">Inbox Zero</a> with a resolution of 24&#x2013;48 hours, which my Special Brain <i>relies heavily on</i> for  mental health.)
</p>

<p>
My preference in the <code>mu4e</code> &ldquo;headers&rdquo; buffer is
</p>

<ul class="org-ul">
<li>to see <b>newest messages first</b> in <code>Archive</code>, <code>Sent</code>, and in arbitrary searches (which can have hundreds or thousands of hits), in order to <i>prioritize recency and relevance</i>, but</li>

<li>to see <b>oldest messages first</b> in <code>Inbox</code>, <code>personal</code>, and <code>work</code>, in order to <i>prioritize pending tasks by age</i>.</li>
</ul>

<p>
Toggling sorting manually was so intolerably <i>not automated by Emacs</i>!
</p>

<p>
So I just wrote a couple of lines of Emacs Lisp. The key symbols to know are <code>mu4e-search-change-sorting</code> and <code>mu4e-search-bookmark-hook</code>.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #595959;">;;; </span><span style="color: #595959;">Inbox-type folders should be sorted 'ascending
</span>(<span style="color: #531ab6;">defcustom</span> <span style="color: #005e8b;">jeh/mu4e-reverse-sort-bookmarks</span> `(
                                             <span style="color: #3548cf;">"maildir:/Inbox"</span>
                                             <span style="color: #3548cf;">"maildir:/work"</span>
                                             <span style="color: #3548cf;">"maildir:/personal"</span>
                                             <span style="color: #3548cf;">"maildir:/Drafts"</span>
                                             <span style="color: #3548cf;">"maildir:/Spam"</span>
                                             <span style="color: #3548cf;">"maildir:/Trash"</span>
                                             ,jeh/mu4e-bookmark-evacuate
                                             ,jeh/mu4e-bookmark-unread
                                             )
  <span style="color: #2a5045;">"Sort these searches `</span><span style="color: #0000b0;">ascending</span><span style="color: #2a5045;">', by OLDEST at top."</span>)

(<span style="color: #531ab6;">defun</span> <span style="color: #721045;">jeh/mu4e-set-sort-order-by-bookmark</span> (search)
  <span style="color: #2a5045;">"Set sort for searches to descending by date, unless the
search was a member of jeh/mu4e-reverse-sort-bookmarks
in which case sort ascending by date."</span>
  (<span style="color: #531ab6;">if</span> (member search jeh/mu4e-reverse-sort-bookmarks)
      (mu4e-search-change-sorting <span style="color: #8f0075;">:date</span> 'ascending)
    (mu4e-search-change-sorting <span style="color: #8f0075;">:date</span> 'decending)
    ))

(add-hook 'mu4e-search-bookmark-hook #'jeh/mu4e-set-sort-order-by-bookmark)
</pre>
</div>

<p>
Ahhhhhhh. <i>That feels better.</i>
</p>

<p>
UPDATE 2026 April 03! There was a niggling bug in this setup: the first time any mu4e search is called, it prompts for a search string. I just fixed it by adding the following lines right after the lines above:
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #595959;">;;; </span><span style="color: #595959;">NOTE! jeh/mu4e-set-sort-order-by-bookmark is a run as a hook
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">by mu4e-search-bookmark. But the former calls mu4e-search-change-sorting
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">which in turn calls mu4e-search-rerun, which will prompt for a search
</span><span style="color: #595959;">;;; </span><span style="color: #595959;">if mu4e--search-last-query is nil.
</span>(<span style="color: #531ab6;">if</span> (not mu4e--search-last-query) (<span style="color: #531ab6;">setq</span> mu4e--search-last-query jeh/mu4e-bookmark-unread))
</pre>
</div>

<p>
This is a perfectly illustrative example of two common patterns in my Emacs journey (1) carefully reading the package that you&rsquo;re customizing helps you to obtain the results that you want; and (2) I am a clumsy dork.
</p>
</div>
</div>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-emacs.html">emacs</a> <a href="https://jamesendreshowell.com/tag-org-mode.html">org-mode</a> </div></div>
]]></description>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[org-mode]]></category>
  <link>https://jamesendreshowell.com/2026-01-08-custom-sorting-of-mu4e-headers.html</link>
  <guid>https://jamesendreshowell.com/2026-01-08-custom-sorting-of-mu4e-headers.html</guid>
  <pubDate>Thu, 08 Jan 2026 13:32:00 -0500</pubDate>
</item>
<item>
  <title><![CDATA[The cowardice of the powerful: educational leadership in DEI]]></title>
  <description><![CDATA[
<div class="post-date">2026 Jan 03</div><blockquote>
<p>
Every year my institution measures faculty productivity by requiring us to submit a report of our annual activities. This year I noticed that two sections had silently disappeared. 
</p>
</blockquote>


<pre class="example" id="org03e7c1a">
Climate and Diversity Activities.
Creating a welcoming climate, thereby maximizing success for all
of our members is an important goal for the college. List your
contributions to this goal here.
</pre>

<pre class="example" id="org96eb3e8">
Increasing the participation of women and under-represented
minorities is an equally important goal at the department,
college and university levels. List the contributions you have
made toward increasing diversity with respect to your
instructional, research and service activities.
</pre>

<blockquote>
<p>
The entries still exist in the awful web platform through which we are forced to submit our responses. But when you generate the report, those headings and any responses are simply not included in the document. There was no announcement, no policy change, just a silent elision of our work. The current university administration was installed in 2022. Although the new provost is a laughable AI-atollah, as far as we can tell none of them seem to be fascists. But in that time we have not been able to construct an instrument sufficiently powerful to detect their integrity.
</p>

<p>
My disgust at this development prompted me to write the following. I submitted an abridged version of it in my portfolio, as space permitted.
</p>

<p>
I feel the need to stress the word &ldquo;disgust.&rdquo;
</p>
</blockquote>
<div id="outline-container-orgd6f06ec" class="outline-2">
<h2 id="orgd6f06ec">Reading history requires context</h2>
<div class="outline-text-2" id="text-orgd6f06ec">
<p>
The continuing attack on &ldquo;diversity, equity, and inclusion&rdquo; must be contextualized within the continuing attack on education broadly. Indeed, in the broadest context, the attack on science itself resembles and reinforces the attack on the arts and humanities. Both attacks share deep historical roots in this culture, and both share the same political aims.
</p>

<p>
Setting personal politics aside&#x2014;setting <i>morality</i> aside&#x2014;there are urgent, strictly professional responsibilities that compel educators to defend these values and the institutional activities that uphold them. 
</p>

<p>
Establishing authority in the classroom requires establishing trust with all of the students. It requires establishing trust between and among all of the students. Carrying out effective pedagogy requires creating an engaging environment for every student. An engaging environment must be many things, but it cannot be a hostile environment.
</p>

<p>
Every component of the educational mission is directly undermined within an institution that permits the perception of indifference to injustice. In short, education requires cooperation, which in turn requires social morality.
</p>
</div>
</div>
<div id="outline-container-org84e0c26" class="outline-2">
<h2 id="org84e0c26">Representing and supporting marginalized students</h2>
<div class="outline-text-2" id="text-org84e0c26">
<p>
My wife and I are both first-generation college graduates. We both have (invisible) disabilities. We both earned bachelor&rsquo;s and doctoral degrees from globally preeminent public universities. We both subsequently devoted our careers to teaching at public universities. (I was also a non-traditional student: I was obliged to leave college without a degree, eked out a living for three years, and returned to finish a bachelor&rsquo;s degree at age 28. Statistically speaking, I dramatically beat the odds.)
</p>

<p>
Education <i>ennobled</i> both of us. Science and literature are ennobling, travel and languages are ennobling, so many of the things for which education opened doors for us have been ennobling. Do you know what else is ennobling? <i>Being able to pay our fucking bills.</i> The security that nobody in our families had enjoyed before we did is ennobling.
</p>

<p>
We both staked our careers on the core belief that we have a responsibility to contribute back to the system that produced us, to uphold the standards of excellence to which we were held, to provide each and every student with all of the support that we received (or, <i>did not receive</i>), and to represent ourselves to our students and to our colleagues as who we are.
</p>

<p>
Incidentally, my maternal grandmother&rsquo;s entire extended family were murdered in Nazi death camps, except for her sister and mother who somehow survived. So I suppose that&rsquo;s another thing to which I am forced to bear witness, including in the classroom.
</p>
</div>
</div>
<div id="outline-container-org9d15597" class="outline-2">
<h2 id="org9d15597">Protecting vulnerable students</h2>
<div class="outline-text-2" id="text-org9d15597">
<p>
What are we even talking about when we say &ldquo;diversity, equity, and inclusion?&rdquo; It means recognizing, at least, this: <i>every person is unique.</i> A human being is not an instantiation of a category. This observation, like many truisms, circumscribes and transcends the fractal outline traced between the trivially mundane and the transcendently profound. This insight is worth ruminating deeply about. It contains the deep meaning of the slogan &ldquo;Representation Matters.&rdquo;
</p>

<p>
Each human exists independently of categories. Conversely, programs of intimidation targeting human categories purposely elicit very real terror in actual individuals.
</p>

<p>
I simply refuse to permit any students to feel threatened in my classroom.
When I noticed that foreign students stopped attending my classes after the immigration raids of early 2025, <i>I took it personally,</i> because it is both a political and a professional affront.
When queer students confide to me their fear of violence on campus, <i>I take it personally,</i>  because it is both a political and a professional affront. I am confronted with students who before my very eyes tremble with the fear of being deported, students who can&rsquo;t afford food, students <i>male and female</i> visibly scarred by a pervasive culture of rape, students who have accustomed themselves to the spectre of mass death from assault rifles in the auditorium&#x2014;all intolerable, all familiar.
</p>

<p>
Threats to our students are <b>direct attacks on the educational mission and tangible disruptions to our work.</b> I repeat: our professional responsibilities compel our active defense of social values. If this conclusion is &ldquo;political,&rdquo; it is because the political, the very ugliest political, has violated the academy.
</p>

<p>
In this context, <i>every educator</i> is called to represent themselves as a visible advocate of civil values. Every institution must protect space for this representation. 
</p>

<p>
Each of these modes of representation matters. Public expression of solidarity matters even more. Institutional support of these values matters even more.
</p>
</div>
</div>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-teaching.html">teaching</a> <a href="https://jamesendreshowell.com/tag-science.html">science</a> <a href="https://jamesendreshowell.com/tag-politics.html">politics</a> </div></div>
]]></description>
  <category><![CDATA[teaching]]></category>
  <category><![CDATA[science]]></category>
  <category><![CDATA[politics]]></category>
  <link>https://jamesendreshowell.com/2026-01-03-educational-leadership-in-dei.html</link>
  <guid>https://jamesendreshowell.com/2026-01-03-educational-leadership-in-dei.html</guid>
  <pubDate>Sat, 03 Jan 2026 23:24:00 -0500</pubDate>
</item>
<item>
  <title><![CDATA[Org mode, LaTeX, and tagged PDFs: producing accessible documents]]></title>
  <description><![CDATA[
<div class="post-date">2025 Dec 29</div><p>
Many of us in higher education use Emacs to produce course materials,
and these <a href="https://www.ada.gov/resources/2024-03-08-web-rule/">must conform to the accessibility requirements of the Americans with Disabilities Act</a>.
We often <a href="https://orgmode.org/manual/LaTeX-Export.html">export Org mode documents to LaTeX to produce very nice PDF output</a>.
But until very recently,
LaTeX could not
<a href="https://www.latex-project.org/news/2024/07/08/tagging/">produce tagged PDFs that conform to the PDF/UA accessibility standard</a>.
Until how recently? Only starting with TeX Live 2025.
</p>

<p>
In short, creating accessible PDFs from Org mode means having to install this new version of <a href="https://tug.org/texlive/">TeX Live</a> (the massive, annually-updated software package of all things TeX and LaTeX). 
I am still on Debian 12, whose <a href="https://wiki.debian.org/TeXLive">stable repositories provide TeX Live 2022</a>.
Even the <a href="https://ubuntu.pkgs.org/25.10/ubuntu-universe-amd64/texlive_2024.20250309-1_all.deb.html">most recent Ubuntu repositories only appear to package TeX Live 2024</a>.
The <a href="https://tug.org/texlive/upgrade.html">advice from the TeX Live maintainers</a> is to remove the <code>.deb</code> installation and install TeX Live 2025 fresh, as below.
</p>

<p>
The steps presented here <b>might</b> work also for Ubuntu and later versions of Debian, but that&rsquo;s only a <b>wildly hopeful speculation that I cannot test</b>.
</p>
<div id="outline-container-orgb44182f" class="outline-2">
<h2 id="orgb44182f">Installing TeX Live 2025 on Debian 12</h2>
<div class="outline-text-2" id="text-orgb44182f">
<p>
Set aside ninety minutes for this installation!
</p>

<p>
I successfully installed TeX Live 2025 on multiple machines running Debian 12 with the following steps.
Note that I closely followed the instructions from the <a href="https://wiki.debian.org/TeXLive">Debian wiki</a> and the <a href="https://tug.org/texlive/quickinstall.html">TeX Live website on TUG</a>.
I have added some clarifying remarks that might be helpful.
</p>
</div>
<div id="outline-container-org9f18ad4" class="outline-3">
<h3 id="org9f18ad4">Uninstall the old <code>.deb</code> version of TeX Live</h3>
<div class="outline-text-3" id="text-org9f18ad4">
<div class="org-src-container">
<pre class="src src-bash">  sudo apt autopurge texlive*
</pre>
</div>
<p>
Just <i>uninstalling</i> TeXLive takes a couple minutes.
If you don&rsquo;t remember when you installed these packages, wait until you see how many dependencies they have. TeX Live is the biggest package you&rsquo;re likely to find installed on any Linux system. (No, I probably don&rsquo;t need every module, but it has always been much easier to install the whole monolith than to deal with missing dependencies.)
</p>
</div>
</div>
<div id="outline-container-org379a96c" class="outline-3">
<h3 id="org379a96c">Install TeX Live 2025 from <a href="https://ctan.org/">CTAN</a></h3>
<div class="outline-text-3" id="text-org379a96c">
<div class="org-src-container">
<pre class="src src-nil">cd /tmp
wget https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
tar xvf install-tl-unx.tar.gz
cd install-tl-2*
sudo perl ./install-tl --no-interaction
</pre>
</div>
<p>
<a href="https://tug.org/texlive/quickinstall.html">The instructions</a> have a cute little note <code># may take several hours to run</code> which prompted my <a href="https://fediscience.org/@jameshowell/115799486957198121">LOL post to Mastodon</a>. (Again, I choose to install everything here, 4,958 TeX Live packages. In fact <a href="https://tug.org/texlive/quickinstall.html">the instructions</a> presume a full install.)
</p>

<p>
It took about an hour on my newish desktop with Ethernet, almost two hours on my ten-year-old laptop over Wi-Fi.
</p>
</div>
</div>
<div id="outline-container-orgdff4be0" class="outline-3">
<h3 id="orgdff4be0">Add the binary directory to your <code>PATH</code></h3>
<div class="outline-text-3" id="text-orgdff4be0">
<p>
It will be of the form <code>/usr/local/texlive/2025/bin/PLATFORM</code>, likely <code>/usr/local/texlive/2025/bin/x86_64-linux</code>.
</p>

<p>
Be certain that root can run the TeX Live binaries too!
<a href="https://askubuntu.com/questions/24937/how-do-i-set-path-variables-for-all-users-on-a-server">The way I did so was to edit <code>/etc/profile</code></a>, find the appropriate lines setting the path, and edit them to add that directory. The result looks like so:
</p>

<div class="org-src-container">
<pre class="src src-sh"><span style="color: #531ab6;">if</span> [ <span style="color: #3548cf;">"$(</span><span style="color: #8f0075;">id -u</span><span style="color: #3548cf;">)"</span> -eq 0 ]; <span style="color: #531ab6;">then</span>
  <span style="color: #005e8b;">PATH</span>=<span style="color: #3548cf;">"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/texlive/2025/bin/x86_64-linux"</span>
<span style="color: #531ab6;">else</span>
  <span style="color: #005e8b;">PATH</span>=<span style="color: #3548cf;">"/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/local/texlive/2025/bin/x86_64-linux"</span>
<span style="color: #531ab6;">fi</span>
<span style="color: #8f0075;">export</span> PATH
</pre>
</div>
</div>
</div>
<div id="outline-container-org9da52cc" class="outline-3">
<h3 id="org9da52cc">Install a few minimal base packages via <code>apt</code></h3>
<div class="outline-text-3" id="text-org9da52cc">
<div class="org-src-container">
<pre class="src src-bash">  sudo apt install tex-common texinfo lmodern 
</pre>
</div>
</div>
</div>
<div id="outline-container-orgfb3d39c" class="outline-3">
<h3 id="orgfb3d39c">Configure a &ldquo;dummy package&rdquo; and install via <code>apt</code></h3>
<div class="outline-text-3" id="text-orgfb3d39c">
<p>
This part is opaque to me. It appears we are using something called <code>equivs</code> to wrap our raw-dog TeX Live install into a <code>.deb</code> in order to trick the package manager into playing nice with it, but I am innocent of the mechanism here.
</p>

<div class="org-src-container">
<pre class="src src-bash">  sudo apt install equivs
  mkdir /tmp/tl-equivs &amp;&amp; <span style="color: #8f0075;">cd</span> /tmp/tl-equivs
  equivs-control texlive-local
</pre>
</div>

<p>
We are now in a temporary directory that contains a configuration file for our dummy package called <code>texlive-local</code>.
Replace the contents of that file with the following:
</p>

<pre class="example" id="org4b2c8c1">
Section: misc
Priority: optional
Standards-Version: 4.1.4

Package: texlive-local
Version: 2025.99999999-1
Maintainer: you &lt;you@yourdomain.example.org&gt;
Provides: asymptote, chktex, cm-super, cm-super-minimal, context,
 dvidvi, dvipng, dvisvgm, feynmf, fragmaster, jadetex, lacheck, 
 latex-cjk-all, latex-cjk-chinese, latex-cjk-chinese-arphic-bkai00mp,
 latex-cjk-chinese-arphic-bsmi00lp, latex-cjk-chinese-arphic-gbsn00lp,
 latex-cjk-chinese-arphic-gkai00mp, latex-cjk-common, latex-cjk-japanese,
 latex-cjk-japanese-wadalab, latex-cjk-korean, latex-cjk-thai, latexdiff,
 latexmk, latex-sanskrit, lcdf-typetools, lmodern, luatex,
 musixtex, preview-latex-style, ps2eps, psutils, purifyeps, t1utils,
 tex4ht, tex4ht-common, tex-gyre, texinfo, texlive, texlive-base,
 texlive-bibtex-extra, texlive-binaries, texlive-common, texlive-extra-utils,
 texlive-fonts-extra, texlive-fonts-extra-doc, texlive-fonts-recommended,
 texlive-fonts-recommended-doc, texlive-font-utils, texlive-formats-extra,
 texlive-games, texlive-humanities, texlive-humanities-doc, 
 texlive-lang-all, texlive-lang-arabic, texlive-lang-cjk, texlive-lang-cyrillic,
 texlive-lang-czechslovak, texlive-lang-english, texlive-lang-european,
 texlive-lang-japanese, texlive-lang-chinese, texlive-lang-korean,
 texlive-lang-french, texlive-lang-german, texlive-lang-greek,
 texlive-lang-italian, texlive-lang-other,
 texlive-lang-polish, texlive-lang-portuguese, texlive-lang-spanish,
 texlive-latex-base, texlive-latex-base-doc, texlive-latex-extra,
 texlive-latex-extra-doc, texlive-latex-recommended,
 texlive-latex-recommended-doc, texlive-luatex, texlive-math-extra,
 texlive-metapost, texlive-metapost-doc, texlive-music,
 texlive-pictures, texlive-pictures-doc, texlive-plain-generic,
 texlive-pstricks, texlive-pstricks-doc, texlive-publishers,
 texlive-publishers-doc, texlive-science, texlive-science-doc, texlive-xetex,
 thailatex, tipa, tipa-doc, xindy, xindy-rules
Depends:
Architecture: all
Description: My local installation of TeX Live 2025.
 A full "vanilla" TeX Live 2025
 http://tug.org/texlive/debian#vanilla
</pre>

<p>
And finally:
</p>

<div class="org-src-container">
<pre class="src src-bash">  equivs-build texlive-local
  sudo dpkg -i texlive-local_2025.99999999-1_all.deb
</pre>
</div>
</div>
</div>
</div>
<div id="outline-container-org06abc93" class="outline-2">
<h2 id="org06abc93">Producing a compliant PDF</h2>
<div class="outline-text-2" id="text-org06abc93">
<p>
Reality check: let&rsquo;s make sure we can in fact use our new TeX Live install to produce a minimal accessible PDF. Note that the <code>polyglossia</code> package is a replacement for the <code>babel</code> package that adds accessibility features. But the <code>\DocumentMetadata{}</code> command does the heavy lifting for producing tagged PDFs. It must come before <code>\documentclass{}</code>.
</p>

<div class="org-src-container">
<pre class="src src-latex">  <span style="color: #531ab6;">\DocumentMetadata</span>{
    lang        = en,
    pdfstandard = ua-2,
    pdfstandard = a-4f,
    tagging     = on
  }

  <span style="color: #531ab6;">\documentclass</span>{<span style="color: #8f0075;">article</span>}

  <span style="color: #531ab6;">\usepackage</span>{<span style="color: #8f0075;">polyglossia</span>}
  <span style="color: #531ab6;">\setdefaultlanguage</span>[variant=US]{english}

  <span style="color: #531ab6;">\begin</span>{<span style="color: #721045;">document</span>}

  <span style="color: #531ab6;">\section</span>{<span style="color: #721045;">Lorem ipsum</span>}

  I know I promised US English but here's some nonsense
  not-quite-Latin. Est eveniet accusamus dolor et. Possimus fugit
  consectetur alias iure suscipit facere est exercitationem. Sed enim
  sapiente atque.

  Voluptas et tempora est. Recusandae velit qui nesciunt. Molestiae excepturi
  occaecati doloribus. Eum sunt optio aut consequatur doloremque. Quo eveniet
  rerum aut dicta impedit quia ut autem. Dolor nisi qui architecto sunt.

  Corporis quidem aut natus est quidem pariatur. Error aut repellat nobis
  velit corporis voluptatem. Libero hic nesciunt omnis ut quam minus soluta.
  Ad quo culpa facere pariatur voluptas et quis nostrum. Pariatur tempore
  ipsum voluptatibus iusto repudiandae. Earum ea quo saepe autem et. Eum
  ratione eaque non dolorum ut fugit vitae dolorum.

  <span style="color: #531ab6;">\end</span>{<span style="color: #721045;">document</span>}
</pre>
</div>

<p>
Save this file as <code>minimal.tex</code> and run
</p>

<div class="org-src-container">
<pre class="src src-bash">lualatex minimal.tex
</pre>
</div>

<p>
(On its first run, it will take a minute to build a font names database.)
</p>

<p>
If it doesn&rsquo;t work, well, I guess you have some debugging to do?
Note that the LuaLaTeX engine is required for all the accessibilty new hotness. (TIL <a href="https://www.texdev.net/2024/11/05/engine-news-from-the-latex-project">it has been the recommended engine for a year</a>.)
</p>
</div>
</div>
<div id="outline-container-org1642b78" class="outline-2">
<h2 id="org1642b78">Configuring Org LaTeX export to produce compliant PDFs</h2>
<div class="outline-text-2" id="text-org1642b78">
<p>
Note that I am stealing everything here from Kenny Ballou&rsquo;s <a href="https://kennyballou.com/blog/2025/08/tagged-pdfs-org-export/index.html">comprehensive and excellent post</a> to which I have little to add.
</p>

<p>
Add these expressions to your Emacs configuration.
</p>

<p>
Set the default engine to <code>lualatex</code> but allow individual files to override it (in case you have some weird old files, I suppose).
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">  (<span style="color: #531ab6;">setq</span> org-latex-compiler <span style="color: #3548cf;">"lualatex"</span>)

  <span style="color: #595959;">;;; </span><span style="color: #595959;">%latex gets replaced with org-latex-compiler
</span>  <span style="color: #595959;">;;; </span><span style="color: #595959;">OR overridden by the #+LATEX_COMPILER header
</span>  (<span style="color: #531ab6;">setq</span> org-latex-pdf-process
        '(<span style="color: #3548cf;">"latexmk -f -pdf -%latex -interaction=nonstopmode -shell-escape -output-directory=%o %f"</span>))
</pre>
</div>

<p>
Insert the <code>\DocumentMetadata{}</code> command before <code>\documentclass{}</code> for the <code>article</code> document type. Note that as written, only the <code>article</code> documentclass is defined for export. You might already have a <code>org-latex-classes</code> declaration in your config, in which case you should modify it to replace the <code>article</code> class definition with this one.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">  (<span style="color: #531ab6;">defvar</span> <span style="color: #005e8b;">org-latex-metadata</span> <span style="color: #3548cf;">"\\DocumentMetadata{lang = en, pdfversion = 2.0, pdfstandard = ua-2, pdfstandard = a-4}"</span>
    <span style="color: #2a5045;">"LaTeX preamble command to specify PDF accessibility metadata.\nIt must appear before the \\documentclass{} declaration."</span>)

  (<span style="color: #531ab6;">setq</span> org-latex-classes
        `(
          (<span style="color: #3548cf;">"article"</span> ,(concat org-latex-metadata <span style="color: #3548cf;">"\n"</span> <span style="color: #3548cf;">"\\documentclass[11pt]{article}"</span>)
           (<span style="color: #3548cf;">"\\section{%s}"</span> . <span style="color: #3548cf;">"\\section*{%s}"</span>)
           (<span style="color: #3548cf;">"\\subsection{%s}"</span> . <span style="color: #3548cf;">"\\subsection*{%s}"</span>)
           (<span style="color: #3548cf;">"\\subsubsection{%s}"</span> . <span style="color: #3548cf;">"\\subsubsection*{%s}"</span>)
           (<span style="color: #3548cf;">"\\paragraph{%s}"</span> . <span style="color: #3548cf;">"\\paragraph*{%s}"</span>)
           (<span style="color: #3548cf;">"\\subparagraph{%s}"</span> . <span style="color: #3548cf;">"\\subparagraph*{%s}"</span>))
        ))
</pre>
</div>

<p>
I have not yet attempted to make the corresponding definition for <code>Beamer</code>. When I get it to work I will update this post.
</p>

<p>
(Note finally that <a href="https://latex.us/macros/latex/required/latex-lab/documentmetadata-support-code.pdf">the <code>testphase</code> key in the <code>\DocumentMetadata{}</code> command has been deprecated</a>, so I&rsquo;ve removed it.)
</p>

<p>
Here is a minimal Org document to test export:
</p>

<pre class="example" id="orga7fd868">
#+title: A nice title for a PDF
#+subtitle: a test of tagged PDF accessibility
#+latex_header: \usepackage{polyglossia}
#+latex_header: \setdefaultlanguage[variant=US]{english}

Est eveniet accusamus dolor et. Possimus fugit consectetur alias
iure suscipit facere est exercitationem. Sed enim sapiente atque.

* Heading 1

** Subhead 1.1
Voluptas et tempora est. Recusandae velit qui nesciunt. Molestiae
excepturi occaecati doloribus.

** Subhead 1.2
Eum sunt optio aut consequatur doloremque. Quo eveniet rerum aut
dicta impedit quia ut autem. Dolor nisi qui architecto sunt.

* Heading 2

** Subhead 2.1
Corporis quidem aut natus est quidem pariatur. Error aut repellat
nobis velit corporis voluptatem. Libero hic nesciunt omnis ut quam
minus soluta. Ad quo culpa facere pariatur voluptas et quis nostrum.

** Subhead 2.2
Pariatur tempore ipsum voluptatibus iusto repudiandae. Earum ea quo
saepe autem et. Eum ratione eaque non dolorum ut fugit vitae
dolorum.
</pre>
</div>
</div>
<div id="outline-container-orgcdfc7c1" class="outline-2">
<h2 id="orgcdfc7c1">Dealing with remaining issues</h2>
<div class="outline-text-2" id="text-orgcdfc7c1">
<p>
It&rsquo;s important to remember that the accessibility functionality in LaTeX is still new and incomplete. But it&rsquo;s a big step from zero to very good.
</p>

<p>
For me and everyone who posts our course materials to Canvas, the touchstone is the &ldquo;Ally Accessibility Checker,&rdquo; which is also not perfect. For instance, it insists that PDFs produced by LaTeX are missing a title when they are not. If I can get to the bottom of that bug, I&rsquo;ll update this post.
</p>
</div>
</div>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-accessibility.html">accessibility</a> <a href="https://jamesendreshowell.com/tag-latex.html">latex</a> <a href="https://jamesendreshowell.com/tag-emacs.html">emacs</a> <a href="https://jamesendreshowell.com/tag-org-mode.html">org-mode</a> <a href="https://jamesendreshowell.com/tag-teaching.html">teaching</a> </div></div>
]]></description>
  <category><![CDATA[accessibility]]></category>
  <category><![CDATA[latex]]></category>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[org-mode]]></category>
  <category><![CDATA[teaching]]></category>
  <link>https://jamesendreshowell.com/2025-12-29-org-mode-latex-and-tagged-pdfs-producing-accessible-documents.html</link>
  <guid>https://jamesendreshowell.com/2025-12-29-org-mode-latex-and-tagged-pdfs-producing-accessible-documents.html</guid>
  <pubDate>Mon, 29 Dec 2025 19:33:00 -0500</pubDate>
</item>
<item>
  <title><![CDATA[What can one person do?]]></title>
  <description><![CDATA[
<div class="post-date">2025 Feb 07</div><p>
I never write poetry. But this one just spilled out.
</p>
<div id="outline-container-org398efe7" class="outline-2">
<h2 id="org398efe7">February 2025</h2>
<div class="outline-text-2" id="text-org398efe7">
<p class="verse">
In the checkout line<br>
&#xa0;&#xa0;&#xa0;we have spoken our broken Spanish in public<br>
&#xa0;&#xa0;&#xa0;with the blushing lady from Mexico.<br>
&#xa0;&#xa0;&#xa0;Sharing photos of our kids, our eyes glimmering.<br>
Immigration agents could not interfere.<br>
<br>
In the vaulted auditoriums<br>
&#xa0;&#xa0;&#xa0;we have taught the sciences,<br>
&#xa0;&#xa0;&#xa0;and we have taught the humanities,<br>
&#xa0;&#xa0;&#xa0;and we will teach them again and again,<br>
&#xa0;&#xa0;&#xa0;even after they withdraw their permission,<br>
&#xa0;&#xa0;&#xa0;even after they take away our paychecks,<br>
&#xa0;&#xa0;&#xa0;even after they lock the auditorium doors.<br>
The ayatollahs of ignorance cannot stop us.<br>
<br>
In the shops and the offices<br>
&#xa0;&#xa0;&#xa0;we have lowered our voices,<br>
&#xa0;&#xa0;&#xa0;we have sealed our trust with handshakes,<br>
&#xa0;&#xa0;&#xa0;and we have signed union cards with grim sincerity.<br>
The billionaire sociopaths were elsewhere, far away.<br>
<br>
Everywhere and always<br>
&#xa0;&#xa0;&#xa0;we have laughed behind the backs of these small men,<br>
&#xa0;&#xa0;&#xa0;ridiculed their macho bullshit,<br>
&#xa0;&#xa0;&#xa0;smirked at the weakness they wear on their sleeves,<br>
&#xa0;&#xa0;&#xa0;laughed at what the small strange men mistake for strength.<br>
Their impotence and their fear shouts louder than their bluster.<br>
<br>
In every encounter with the vulnerable<br>
&#xa0;&#xa0;&#xa0;we extended welcome and we reflected dignity,<br>
&#xa0;&#xa0;&#xa0;we have found a kind word to say,<br>
&#xa0;&#xa0;&#xa0;we have wryly promised the trans kid<br>
&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;that we will hide her in our attic.<br>
Let the bile spill from the monsters’ whiny little mouths.<br>
<br>
From the clutches of the hateful ghouls, right out of their laps,<br>
&#xa0;&#xa0;&#xa0;we have snatched back the teachings of Jesus.<br>
&#xa0;&#xa0;&#xa0;With each gesture of humanity we enter the Kingdom of God.<br>
&#xa0;&#xa0;&#xa0;Their vengeful god is absent: we exalt love in its place.<br>
The false prophets stumble, twisted and naked. Sawdust falls from their eyes.<br>
<br>
At every turn<br>
&#xa0;&#xa0;&#xa0;our empathy exposes us as lunatics and perverts:<br>
&#xa0;&#xa0;&#xa0;fanatics for compassion, wild-eyed enemies of lawlessness,<br>
&#xa0;&#xa0;&#xa0;extremists for education, militants for medicine.<br>
The shameless vilify us—they ennoble us with their lies.<br>
<br>
Under fluorescent lights, in countless unlikely spots,<br>
&#xa0;&#xa0;&#xa0;we come together and we build the third places.<br>
&#xa0;&#xa0;&#xa0;We reveal to one another our numbers.<br>
&#xa0;&#xa0;&#xa0;In the third places, we need not gasp: we can breathe.<br>
&#xa0;&#xa0;&#xa0;In the third places, we inhale sanity—we fill our lungs with belonging.<br>
They rampage and they destroy. We build and we build.<br>
<br>
<br>
We will look back and marvel at what little effort it took to reject surrender.<br>
<br>
We will look back and rejoice that we did not fail to find our courage.<br>
<br>
</p>
</div>
</div>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-poem.html">poem</a> <a href="https://jamesendreshowell.com/tag-politics.html">politics</a> </div>]]></description>
  <category><![CDATA[poem]]></category>
  <category><![CDATA[politics]]></category>
  <link>https://jamesendreshowell.com/2025-02-07-what-can-one-person-do.html</link>
  <guid>https://jamesendreshowell.com/2025-02-07-what-can-one-person-do.html</guid>
  <pubDate>Fri, 07 Feb 2025 00:00:00 -0500</pubDate>
</item>
<item>
  <title><![CDATA[The right to privacy: embodied in each of us]]></title>
  <description><![CDATA[
<div class="post-date">2024 Sep 08</div><p>
On Mastodon, someone in my timeline [update 2025: on an instance that is now gone, alas] asked how to debunk the anti-privacy argument that goes “If you have nothing to hide, you have nothing to fear.”
</p>

<p>
My response was too long for one toot.
</p>

<blockquote>
<p>
Was <a href="https://en.wikipedia.org/wiki/Diogenes">Diogenes</a> correct? When he taught by example that if we are honest, we should carry out openly and in the public square all of our bodily functions? That we should do all our peeing and pooping and barfing and ejaculating in public? By one small step, that we should change our babies’ diapers and embrace our loved ones and caress our lovers, only in public?
</p>

<p>
Privacy is so fundamental that it <i>resides in the human body.</i> It expands outward in concentric circles starting with your physical contact with loved ones. Would you prefer to be the one who draws the outer circle for yourself?
</p>

<p>
Or would you prefer to leave the outer circle to be drawn by &#x2026; global mega-corporations? &#x2026; by a State with the power of violence over you?
</p>
</blockquote>

<p>
Of course, <a href="https://redlib.catsarch.com/r/IAmA/comments/36ru89/just_days_left_to_kill_mass_surveillance_under/crglgh2/">Edward Snowden put it best</a>:
</p>

<blockquote>
<p>
Arguing that you don’t care about privacy because you have nothing to hide is no different than saying you don’t care about free speech because you have nothing to say.
</p>
</blockquote>

<p>
Alas! Snowden made this statement <i>on Reddit</i> during an AMA. I wonder how long this primary source will even exist. Spare a thought for the plight of twenty-first century librarians. 
</p>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-privacy.html">privacy</a> <a href="https://jamesendreshowell.com/tag-philosophy.html">philosophy</a> </div>]]></description>
  <category><![CDATA[privacy]]></category>
  <category><![CDATA[philosophy]]></category>
  <link>https://jamesendreshowell.com/2024-09-08-the-right-to-privacy-embodied-in-each-of-us.html</link>
  <guid>https://jamesendreshowell.com/2024-09-08-the-right-to-privacy-embodied-in-each-of-us.html</guid>
  <pubDate>Sun, 08 Sep 2024 00:00:00 -0400</pubDate>
</item>
<item>
  <title><![CDATA[Just a theory: the flat earth vs. evolution]]></title>
  <description><![CDATA[
<div class="post-date">2024 Sep 06</div><p>
One of my proudest moments as a father went like this. I asked my fifteen-year-old son:
</p>

<blockquote>
<p>
Say you have a telephone pole in Pennsylvania. And another telephone pole in Argentina. What is the angle between the two telephone poles?
</p>
</blockquote>

<p>
He thought for a second. &ldquo;How far away are they from each other?&rdquo;
</p>

<p>
&ldquo;Say 6,000 miles.&rdquo;
</p>

<p>
He thought for another second. &ldquo;Ninety degrees.&rdquo;
</p>

<p>
"That&rsquo;s correct! How did you get it?
</p>

<p>
&ldquo;Well, the Earth is 8,000 miles in diameter, so pi times 8,000 is roughly 24,000 miles. And 6,000 is one quarter of 24,000, so it&rsquo;s a ninety degree angle.&rdquo;
</p>

<p>
I was super proud that he knew the diameter of the Earth, but I was even more proud that he had the ability to make the calculation. The calculation itself is trivial: in my experience, anyone can <i>carry out</i> this calculation. But most people lack the <i>confidence</i> to get to the calculation step.
</p>

<p>
<div style="text-align:center;">* * *</div>
</p>

<p>
When I first started dating my now-wife, her father (my now-father-in-law, my kids&rsquo; now-grandfather) loved to &ldquo;show me how much he likes me&rdquo; by quizzing me. The first time I visited he opened the dictionary and tried to find words that I couldn&rsquo;t define. He never found one, and he was <i>pissed</i>. (But it still made a good impression.)
</p>

<p>
When we&rsquo;d been married a few years, we had a chance to visit Argentina. Both of my wife&rsquo;s parents were nervous about our flying abroad. To ease the tension, and to mess with me, my father in law asked me:
</p>

<blockquote>
<p>
Say you have a telephone pole in Pennsylvania. And another telephone pole in Argentina. What is the angle between the two telephone poles?
</p>
</blockquote>

<p>
I had just looked at the plane ticket (back when you got a paper boarding pass in advance) and saw that we were each about to earn 6,000 miles. I thought for a couple seconds, and I got the same answer the same way my kid did twenty years later&#x2014;but not <i>quite</i> as fast. My father-in-law was <i>pissed</i>. (But it still made a good impression.)
</p>

<p>
<div style="text-align:center;">* * *</div>
</p>

<p>
When we got to Argentina, it was totally mind-blowing to us how <i>plain weird</i> it was to be in the Southern Hemisphere. We flew a few days before New Year&rsquo;s Eve, and going from the shortest darkest days of winter to the longest loveliest days of summer was wonderful! (The return trip was too depressing for words.) Having Orion <i>on the other side of the sky</i>, and all the other constellations <i>unfamiliar</i>, was an experience I found disorienting to the point of terror. We kept getting turned around, trying to navigate Buenos Aires and Córdoba, because we kept unconsciously orienting ourselves with the sun to the south&#x2014;except <i>the sun was on the north side of the sky.</i>
</p>

<p>
And then, walking one night through the balmy December streets of Córdoba, we saw an owl fly through the cone of light under a streetlamp. That was memorable enough. But then I looked at the moon, almost full. And it wasn&rsquo;t the familar face of the moon.
</p>

<p>
The face of the moon was <i>rotated ninety degrees.</i>
</p>

<p>
<div style="text-align:center;">* * *</div>
</p>

<p>
I tell these stories every year in my &ldquo;Genetics, Ecology, and Evolution&rdquo; course. They are not at all relevant to those topics directly, but they are a withering rebuke to the idea that &ldquo;eVoLuTiOn iS OnLy a tHeOrY.&rdquo; It&rsquo;s easy to mock the flat-earthers, but <i>how do you know</i> that the Earth is a sphere? How do you know that the moon orbits the Earth and the Earth orbits the sun? Photos from space don&rsquo;t count: all of your evidence has to come from your own direct experience.
</p>

<p>
The idea that the Earth is a sphere in a heliocentric system is a <i>theory.</i> It is built from a very large set of observations within a <i>mechanistic model</i> in which:
</p>

<ul class="org-ul">
<li>every observation is consistent with all the others, and the model, and</li>

<li>the model is sufficiently sophisticated to make predictions that can be tested, and</li>

<li>all of the observations made to test the predictions are consistent with all other observations, and with the mechanistic model.</li>
</ul>

<p>
This is devastating to the flat-earth model, because its explanatory and predictive power is <i>total garbage</i> compared to the consensus model. This model has gained consensus not because NASA and Google profit, somehow, by deceiving you. The consensus model has gained consensus because of its success.
</p>

<p>
It has been rather disappointing how few of my university students exhibit the confidence to calculate the angle subtended between New York and Buenos Aires. But that is a topic for another time.
</p>

<p>
It has been perfectly brilliant to see how many of my students come to understand the power of the scientific method&#x2014;and especially the might of scientific theory&#x2014;by confronting, <i>and then overcoming,</i> their own inability to convince me, pretending not to believe the Earth is round.
</p>
<div class="taglist"><a href="https://jamesendreshowell.com/tags.html">tags</a>: <a href="https://jamesendreshowell.com/tag-teaching.html">teaching</a> <a href="https://jamesendreshowell.com/tag-science.html">science</a> </div>]]></description>
  <category><![CDATA[teaching]]></category>
  <category><![CDATA[science]]></category>
  <link>https://jamesendreshowell.com/2024-09-06-just-a-theory-the-flat-earth-vs-evolution.html</link>
  <guid>https://jamesendreshowell.com/2024-09-06-just-a-theory-the-flat-earth-vs-evolution.html</guid>
  <pubDate>Fri, 06 Sep 2024 20:49:00 -0400</pubDate>
</item>
</channel>
</rss>
