<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/assets/atom.xsl" type="text/xsl"?><feed
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:thr="http://purl.org/syndication/thread/1.0"
	xml:lang="en-US"
	><title>Sacha Chua - category - blogging</title>
	<subtitle>Emacs, sketches, and life</subtitle>
	<link rel="self" type="application/atom+xml" href="https://sachachua.com/blog/category/blogging/feed/atom/index.xml" />
  <link rel="alternate" type="text/html" href="https://sachachua.com/blog/category/blogging" />
  <id>https://sachachua.com/blog/category/blogging/feed/atom/index.xml</id>
  <generator uri="https://11ty.dev">11ty</generator>
	<updated>2025-09-14T21:17:38Z</updated>
<entry>
		<title type="html">Anchoring my thoughts with a sketch</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2025/09/anchoring-my-thoughts-with-a-sketch/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2025-09-14T21:17:38Z</updated>
    <published>2025-09-14T21:17:38Z</published>
    <category term="drawing" />
<category term="writing" />
<category term="blogging" />
		<id>https://sachachua.com/blog/2025/09/anchoring-my-thoughts-with-a-sketch/</id>
		<content type="html"><![CDATA[<p>
</p><div class="sketch-full"><a class="photoswipe" href="https://sketches.sachachua.com/filename/2025-09-12-07%20Anchoring%20my%20thoughts%20with%20a%20sketch%20&#45;&#45;%20drawing%20writing%20blogging.jpeg" data-src="https://sketches.sachachua.com/static/2025-09-12-07%20Anchoring%20my%20thoughts%20with%20a%20sketch%20&#45;&#45;%20drawing%20writing%20blogging.jpeg" data-title="2025-09-12-07 Anchoring my thoughts with a sketch &#45;&#45; drawing writing blogging" data-w="2873" data-h="2055"><picture>
      <img src="https://sketches.sachachua.com/static/2025-09-12-07%20Anchoring%20my%20thoughts%20with%20a%20sketch%20&#45;&#45;%20drawing%20writing%20blogging.jpeg" width="2873" height="2055" alt="2025-09-12-07 Anchoring my thoughts with a sketch &#45;&#45; drawing writing blogging" loading="lazy" style="max-height: 90vw; height: auto; width: auto" decoding="async">
      <figcaption>2025-09-12-07 Anchoring my thoughts with a sketch &#45;&#45; drawing writing blogging</figcaption>
    </picture></a></div>
<p></p>

<details class="code-details" style="padding: 1em;
                 border-radius: 15px;
                 font-size: 0.9em;
                 box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;">
                  <summary><strong>Text and links from sketch</strong></summary>
<p>
Anchoring my thoughts with a sketch
</p>

<p>
I keep most of my notes in text files. This is great for searching, but the sameness of the typography makes things blur together.
</p>

<p>
I have to read a lot to remember what things felt like, and I still feel so much is missing. Some people can evoke lush word-pictures. I'm not there yet.
</p>

<p>
Lately I've been giving myself more time to draw, to <a href="https://sachachua.com/blog/2025/08/colours/">colour</a>, to doodle.
</p>

<p>
"Today: A+ kept giving me hugs as we walked home from the supermarket."
</p>

<p>
Even my simple sketches give me a surprisingly good sense of what I felt, what I cared about.
</p>

<p>
<a href="https://sachachua.com/blog/2020/06/pythonfontforgeorg-i-made-a-font-based-on-my-handwriting/">I made a font from my handwriting</a>, but real handwritten text says so much more.
</p>

<p>
Comics are very expressive. I wonder how they do that.
How do they draw something so specific and yet so resonant?
</p>

<p>
I take a tangled thought, coax a bit of it into a drawing, and see where that takes me.
</p>

<p>
"A drawing is simply a line going for a walk." - Paul Klee
</p>

<p>
Sometimes I do an audio braindump to feel my way around it or to capture lots of details. That gives me a wall of text. Too much, and at the same time, not enough.
</p>

<p>
I might try to make an outline and expand it, but I often lose steam.
</p>

<p>
I like organizing and fleshing out the sketch. Drawing it is fun.
</p>

<p>
Then I can write the text. I often add lots of details and links. Sometimes I feel lost in the weeds. The sketch becomes my map.
</p>

<p>
I want to finish writing so that you can see my sketch!
(and so it makes sense to you and my future self)
</p>

<p>
Sometimes I just keep playing with the drawing until something interesting emerges.
</p>

<p>
<a href="https://sach.ac/2025-09-12-07">https://sach.ac/2025-09-12-07</a>
</p>


</details>

<p>
I've been drawing more lately. It's slow, but more
fun. I like looking at my sketches from years ago.
I think I will like these ones years from now.
</p>

<p>
I feel like drawings do a good job of reminding me
what I feel about a topic, why I want to write
about it, and what the overall shape of the topic
is, which is important so that I don't run out of
steam a couple thousand words into a post.
The drawing also encourages me to finish the
post so that I can put it out there.
</p>

<p>
Other related posts:
</p>

<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2025/07/my-emacs-writing-experience/">My Emacs writing experience</a> (2025) - how the text side works</li>
<li><a href="https://sachachua.com/blog/2025/07/finding-the-shape-of-my-thoughts/">Finding the shape of my thoughts</a> (2025) - similar to this one</li>
<li><a href="https://sachachua.com/blog/2025/01/through-blogging-we-discover-our-thoughts-and-other-people/">Through blogging, we discover our thoughts and other people</a> (2025)</li>
<li><a href="http://localhost:8080/blog/2024/11/updating-my-audio-braindump-workflow-to-take-advantage-of-whisperx/">Updating my audio braindump workflow to take advantage of WhisperX</a> (2024)</li>
<li><a href="https://sachachua.com/blog/2024/10/how-sketchnotes-fit-into-my-personal-knowledge-management/">How sketchnotes fit into my personal knowledge management</a> (2024)</li>
<li><a href="https://sachachua.com/blog/2013/10/integrating-visual-outlining-into-my-writing-process/">Integrating visual outlining into my writing process</a> (2013)</li>
<li><a href="https://sachachua.com/blog/2023/12/2023-12-25-07-flow-of-ideas-writing-metaphor/">Working with the flow of ideas</a> (2023)</li>
<li><a href="https://sachachua.com/blog/2015/06/working-with-fragmented-thoughts/">Working with fragmented thoughts</a> (2015)</li>
<li><a href="https://sachachua.com/blog/2015/01/drawing-thoughts-index-cards/">Drawing thoughts on index cards</a> (2015)</li>
<li><a href="https://sachachua.com/blog/2013/11/how-i-organize-and-publish-my-sketches/">How I organize and publish my sketches</a> (2013) I don't use Flickr and Evernote any more. I <a href="https://sachachua.com/blog/2016/01/building-simple-sketch-navigator/">built</a>
my own <a href="https://sketches.sachachua.com">sketch viewer</a>, and I use text files in the same directory as my sketches to make them locally searchable.</li>
</ul>

<p>
Elsewhere:
</p>

<ul class="org-ul">
<li><p>
<a href="https://www.getyourselfoptimized.com/shaping-ideas-and-remembering-experiences-through-sketchnotes-mike-rohde/">Shaping Ideas and Remembering Experiences Through Sketchnotes with Mike Rohde - Get Yourself Optimized</a>
</p>
<blockquote>
<p>
I find when I look back over these notes that the memories really come flooding back in really high detail because then, I spent a little more time documenting when I [relive it].
</p>
</blockquote></li>
<li><a href="https://uxplanet.org/sketching-and-reflecting-how-giving-yourself-time-space-unlocks-hidden-potential-in-your-live-2bf0a99e77db">Sketching and Reflecting. I’ve been using visual thinking… | by Chris Spalton | UX Planet</a> - getting more out of reviewing and reflecting on sketchnotes</li>
<li><a href="https://digitalcommons.buffalostate.edu/cgi/viewcontent.cgi?article=1362&amp;context=creativeprojects">Practical skill building and application of sketchnoting and visual thinking</a> (Troy Schubert). I think the section on "Deeper Thinking: Cliché to Metaphor" might be good for expanding my visual vocabulary, and figure 31 (Polarity Management – Results of Self-Facilitation) reminds me of how I like to use sketches to explore my thoughts.</li>
</ul>
<div><a href="https://sachachua.com/blog/2025/09/anchoring-my-thoughts-with-a-sketch/index.org">View org source for this post</a></div><p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2025%2F09%2Fanchoring-my-thoughts-with-a-sketch%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Writing into the quiet</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2025/09/writing-into-the-quiet/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2025-09-10T00:47:12Z</updated>
    <published>2025-09-08T16:58:28Z</published>
    <category term="blogging" />
		<id>https://sachachua.com/blog/2025/09/writing-into-the-quiet/</id>
		<content type="html"><![CDATA[<p>
</p><div class="sketch-full"><a class="photoswipe" href="https://sketches.sachachua.com/filename/2025-09-08-02%20Writing%20into%20the%20quiet%20&#45;&#45;%20blogging.jpeg" data-src="https://sketches.sachachua.com/static/2025-09-08-02%20Writing%20into%20the%20quiet%20&#45;&#45;%20blogging.jpeg" data-title="2025-09-08-02 Writing into the quiet &#45;&#45; blogging" data-w="2900" data-h="2050"><picture>
      <img src="https://sketches.sachachua.com/static/2025-09-08-02%20Writing%20into%20the%20quiet%20&#45;&#45;%20blogging.jpeg" width="2900" height="2050" alt="2025-09-08-02 Writing into the quiet &#45;&#45; blogging" loading="lazy" style="max-height: 90vw; height: auto; width: auto" decoding="async">
      <figcaption>2025-09-08-02 Writing into the quiet &#45;&#45; blogging</figcaption>
    </picture></a></div>
<p></p>

<details class="code-details" style="padding: 1em;
                 border-radius: 15px;
                 font-size: 0.9em;
                 box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;">
                  <summary><strong>Text and links from sketch</strong></summary>
<p>
Writing into the quiet
2025-09-08-02
</p>

<p>
There's a conversation <sup><a id="fnr.1" class="footref" href="https://sachachua.com/blog/feed/atom/index.xml#fn.1" role="doc-backlink">1</a></sup> about whether blogging
is lonely
and I wanted to reflect on that
from the perspective of 24ish years
of sharing notes on my
idiosyncratic interests.
Blog conversations remind me
of the Great Conversation
between book authors<sup><a id="fnr.2" class="footref" href="https://sachachua.com/blog/feed/atom/index.xml#fn.2" role="doc-backlink">2</a></sup>
sometimes with centuries
in between. In contrast, blogs.
are quick, open, convivial.
</p>

<p>
When it comes to developing ideas,
I like public writing more than
the ephemeral cacophany of
in-person conversations,
social media @replies
or private e-mails.
</p>

<p>
My notes are often for my present understanding
and sometimes for my future selves.
If they resonate with others: bonus!
</p>

<p>
I think this might be a useful way to think about it.
</p>

<p>
Write out of self-interest.
Leave the door open for serendipity
</p>

<p>
Then it's not about
"No one's liking or commenting"
or even
"Why can't I find other people like me"
</p>

<p>
It's more like:
I'll keep exploring and taking notes, because it's fun.
Maybe I'll bump into others and swap notes someday. Who knows?
</p>


</details>

<p>
There's a conversation about feeling lonely while
blogging that echoes through the years. Here's a
recent instance: <a href="https://thehistoryoftheweb.com/do-blogs-need-to-be-so-lonely/">Do blogs need to be so lonely? -
The History of the Web</a>; I also liked <a href="https://birming.com/2025/09/07/the-silent-applause/">The silent
applause | Robert Birming</a> and <a href="https://manuelmoreale.com/blogs-don-t-need-to-be-so-lonely">Blogs don’t need to
be so lonely – Manu</a>. Me, I mostly write for
myself, and I don't feel particularly lonely doing
so. It's a pleasant surprise whenever I hear from
someone, but it's not my main goal. I'm content to
plod along, trying to untangle my thoughts and
leave some breadcrumbs for my future self. This
has been very handy not only for technical posts,
but also for things like being able to remember
what it was like to be a twenty-something. Writing
into the quiet without expecting a reply is like
enjoying a comfortably silent beach and
occasionally being delighted when you discover
someone else's message in a bottle.
</p>

<p>
Blog conversations are so much faster than book
conversations. We don't have to pass through
publishing gatekeepers, we don't have to wait
years&hellip; just ideas bouncing back and forth.
Marvelous.
</p>

<p>
Commenting is easier than writing from scratch, so
it would be nice to give people that space to
share their follow-on thoughts more easily, but
it's becoming more of a hassle as parts of the Web
become more hostile. (Thanks, spammers and
advertising cookie-trackers.) <a href="https://sachachua.com/blog/2025/03/moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site/">I turned off
comments on my blog</a> back in March as Disqus had
gotten overbearing with ads and tracking. I didn't
feel like figuring out another commenting service
or self-hosting my own. I don't miss wading
through all the spam. I do miss the ease of public
comments and the tips people shared, mostly
because it was convenient to see and share those
replies in one place. Still, there's space for
commentary. Some people comment via Mastodon or
their own blogs. Once in a blue moon, a post will
strike enough of a chord to get shared via Reddit
or something like that. And there's always e-mail.
</p>

<p>
I like <a href="https://indieweb.org/blog_carnival">blog carnivals</a>: someone proposes a theme,
people can choose to write about it, and the host
links to all those posts for easier discovery.
There's one for <a href="https://indieweb.org/IndieWeb_Carnival">IndieWeb</a> and there's one for
<a href="https://www.emacswiki.org/emacs/Carnival">Emacs</a>. It's fun seeing all these different takes
on the same topic.
</p>

<p>
I wish it was easier for more people to share what
they've been figuring out. I don't think the
technology is the limiting factor. My mom used to
keep a blog on Blogger, and she also wrote some
posts in the self-hosted Wordpress I'd set up for
her before. My sister writes long stories on
Facebook and Instagram so that she can untangle
her thoughts and capture the memories. Never mind
that Facebook is a walled garden that's hard to
follow outside its algorithmic feed; at least
she's writing. I think it's more that the process
of sitting down and turning your thoughts into
words takes time and energy. That's the hard part,
but that's also what's worthwhile. You can't skip
it by using a large language model.
</p>

<p>
Is writing lonely? I wish more people had the
space to sit with their thoughts and figure them
out, and I wish they were easier to find. I'll
settle for reaching across time and space: to my
future self, for sure, and maybe to others whom I
may or may not interact with. Send enough bottles
out to sea, comb the beach often enough, and I'll
find plenty of people who like to take that quiet,
thoughtful approach to life (even as we gently
poke fun at ourselves for possibly overthinking
things). Fortunately, if they blog, it's easy to
keep in touch lightly: not limited by anyone's
energy or interest at a particular point in time,
but just open to serendipity.
</p>

<div class="center-doodle" id="org20b4a15">

<figure id="org8e1197d">
<img src="https://sachachua.com/blog/2025/09/writing-into-the-quiet/2025-09_16.jpeg" alt="A message in a bottle" style="max-height:100px">

</figure>

</div>

<div class="update" id="orgdb1dd21">
<p>
<span class="timestamp-wrapper"><time class="timestamp" datetime="2025-09-09">[2025-09-09 Tue]</time></span>: A few more thoughts I want to connect to this one:
</p>
<ul class="org-ul">
<li>Henrik Karlsson's essay on <a href="https://www.henrikkarlsson.xyz/p/search-query">writing as a search query for people</a></li>
<li>I came across <a href="https://twilightjournal.com/">Twilight Journal</a> via <a href="https://www.reddit.com/r/Stoicism/">r/stoicism</a> today, so I wanted to link to that too. Messages in bottles.</li>
<li>And another thought about the night sky and how it's filled with stars, even though there are unimaginable spaces between them&hellip; (Not that I've seen a clear night sky lately, but I have one clear memory of it as a child that stays with me.)</li>
</ul>

</div>
<div id="blog-2025-09-writing-into-the-quiet-footnotes">
<h3 class="footnotes">Footnotes</h3>
<div id="blog-2025-09-writing-into-the-quiet-text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="https://sachachua.com/blog/feed/atom/index.xml#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Here's a recent instance: <a href="https://thehistoryoftheweb.com/do-blogs-need-to-be-so-lonely/">Do blogs need to
be so lonely? - The History of the Web</a>. I also
liked <a href="https://birming.com/2025/09/07/the-silent-applause/">The silent applause | Robert Birming</a> and
<a href="https://manuelmoreale.com/blogs-don-t-need-to-be-so-lonely">Blogs don’t need to be so lonely – Manu</a>.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="https://sachachua.com/blog/feed/atom/index.xml#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
I picked up this idea from Adler and van Doren's <a href="https://sachachua.com/blog/2012/03/visual-book-notes-how-to-read-a-book/">How to Read a Book</a> and the idea of syntopical reading.
</p></div></div>


</div>
</div><div><a href="https://sachachua.com/blog/2025/09/writing-into-the-quiet/index.org">View org source for this post</a></div><p>You can <a href="https://social.sachachua.com/@sacha/statuses/01K4NBAFRBJMS15Z14JRHPPKFT" target="_blank" rel="noopener noreferrer">comment on Mastodon</a>, <a href="https://sachachua.com/blog/2025/09/writing-into-the-quiet/#comment">view 1 comment</a>, or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2025%2F09%2Fwriting-into-the-quiet%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Working on the plumbing in a small web community</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2025/05/working-on-the-plumbing-in-a-small-web-community/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2025-06-01T03:51:15Z</updated>
    <published>2025-06-01T03:51:15Z</published>
    <category term="community" />
<category term="connecting" />
<category term="emacs" />
<category term="blogging" />
		<id>https://sachachua.com/blog/2025/05/working-on-the-plumbing-in-a-small-web-community/</id>
		<content type="html"><![CDATA[<p>
The IndieWeb Carnival prompt for May is <a href="https://thoughts.uncountable.uk/may-2025-indieweb-carnival-small-web-communities/">small web
communities</a>. I've been exploring some thoughts on
how a little effort goes a long way to connecting
a community. Sometimes I think of it as working on
the plumbing so that ideas can flow more smoothly.
It feels a little different from the direct
contribution of knowledge or ideas. I also want to
connect with other people who do this kind of
thing.
</p>

<p>
Emacs is a text editor that has been around since
the 1970s. It's highly programmable, so people
have come up with all sorts of ways to modify it
to do what they want. It's not just for
programmers. My favourite examples include
<a href="https://www.reddit.com/r/emacs/comments/1ktzgpx/comment/mtxvf7o/">novelists</a> and <a href="https://bofh.org.uk/2019/02/25/baking-with-emacs/">bakers</a> and <a href="http://mokrzu.github.io/clojure/clojure-music.html">musicians</a> who use Emacs
in unexpected ways. Because Emacs is so flexible,
community is important. The source code and
documentation don't show all the possible
workflows. As people figure things out by
themselves and together, more possibilities open
up.
</p>

<p>
I love tweaking Emacs to help me with different
things I want to do, and I love learning about how
other people use it too. I've been sharing my
notes on Emacs on this blog since 2001 or so. In
2015, as I was getting ready to become a parent, I
knew I was going to have much less time and
focused attention, which meant less time playing
with Emacs. Fortunately, around that time, John
Wiegley (who was one of the maintainers of Emacs
at the time) <a href="https://lists.gnu.org/archive/html/emacs-devel/2015-10/msg01425.html">suggested</a> that it would be helpful if
I could keep an eye on community updates and
summarize them. This worked well with the
fragmentation of my time, since I could still
speed-read updates and roughly categorize them.
</p>

<p>
</p><div class="sketch-full"><a class="photoswipe" href="https://sketches.sachachua.com/filename/2024-01-31-05%20Community%20plumbing%20%23emacs%20%23community.png" data-src="https://sketches.sachachua.com/static/2024-01-31-05%20Community%20plumbing%20%23emacs%20%23community.png" data-title="2024-01-31-05 Community plumbing #emacs #community" data-w="2808" data-h="3744"><picture>
      <img src="https://sketches.sachachua.com/static/2024-01-31-05%20Community%20plumbing%20%23emacs%20%23community.png" width="2808" height="3744" alt="2024-01-31-05 Community plumbing #emacs #community" loading="lazy" style="max-height: 90vw; height: auto; width: auto" decoding="async">
      <figcaption>2024-01-31-05 Community plumbing #emacs #community</figcaption>
    </picture></a></div>
<p></p>

<details class="code-details" style="padding: 1em;
                 border-radius: 15px;
                 font-size: 0.9em;
                 box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;">
                  <summary><strong>Text from sketch</strong></summary>
<p>
Community plumbing
</p>

<p>
You don't have to fill the pipes all by yourself. Just help things flow.
</p>

<p>
I want to share some of the things we're doing in the Emacs community
so that I can convince you that building plumbing for your community can be fun, easy, and awesome.
This is great because enthusiasm spreads.
</p>

<p>
virtuous cycle
</p>

<ul class="org-ul">
<li>Other places: YouTube, Reddit, HN, lobste.rs, Mastodon, PeerTube, mailing lists&#x2026;.</li>
<li>Blog aggregator
<ul class="org-ul">
<li><a href="https://planet.emacslife.com">Planet Emacs Life</a> (uses Planet Venus) - update: <span class="timestamp-wrapper"><span class="timestamp">[2025-05-31 Sat] </span></span> I wrote my own RSS feed aggregator instead.</li>
</ul></li>
<li>Newsletter: <a href="https://sachachua.com/blog/category/emacs-news">Emacs News</a>, 1-2 hours a week
<ul class="org-ul">
<li>summarize &amp; group</li>
<li>announce calendar events</li>
</ul></li>
<li><a href="https://www.emacswiki.org/emacs/Usergroups">User groups</a>
<ul class="org-ul">
<li>[often use Emacs News to get conversations going]</li>
</ul></li>
<li>iCal &amp; Org files: <a href="http://emacslife.com/calendar">Emacs Calendar</a></li>
<li>Conference
<ul class="org-ul">
<li><a href="https://emacsconf.org">EmacsConf</a>: &lt; USD 50 hosting costs + donated server + volunteer time</li>
</ul></li>
</ul>

<p>
Tips:
</p>

<ul class="org-ul">
<li>Make it fun for yourself.</li>
<li>Build processes and tools.</li>
<li>Let people help</li>
</ul>

<p>
2024-01-31-05
</p>


</details>

<p>
Some more notes on the regular flows built up by
this kind of community plumbing:
</p>

<p>
<b>Daily:</b> Lots of people post on <a href="https://reddit.com/r/emacs">reddit.com/r/emacs</a>
and on Mastodon with the #emacs hashtag. I also
aggregate Emacs-related blog posts at
<a href="https://planet.emacslife.com">planet.emacslife.com</a>, taking over from
planet.emacsen.org when Tess had DNS issues. There
are a number of active channels on YouTube and
occasionally some on PeerTube instances as well. I
don't need to do much work to keep this flowing,
just occasionally adding feeds to the aggregator
for planet.emacslife.com.
</p>

<p>
<b>Weekly:</b> I collect posts from different sources,
remove duplicates, combine links talking about the
same thing, categorize the links, put them roughly
in order, and post <a href="https://sachachua.com/blog/category/emacs-news">Emacs News</a> to a website, an RSS
feed, and a mailing list. This takes me maybe 1.5
hours each week. It's one of the highlights of my
week. I get to learn about all sorts of cool
things.
</p>

<p>
Weekly seems like a good rhythm for me considering
how active the Emacs community is. Daily would be
too much time. Monthly would lead to either too
long of a post or too much lost in curation, and
the conversations would be delayed.
</p>

<p>
Sometimes I feel a twinge of envy when I check out
other people's newsletter posts with commentary or
screenshots or synthesis. (So cool!) But hey, I'm
still here posting Emacs News after almost ten
years, so that's something. =) A long list of
categorized links fits the time I've got and the
way my mind works, and other people can put their
own spin on things.
</p>

<p>
<b>Monthly:</b> There are a number of <a href="https://www.emacswiki.org/emacs/Usergroups">Emacs user
groups</a>, both virtual and in-person. Quite a few of
them use Emacs News to get the discussion rolling
or fill in gaps in conversation, which is
wonderful.
</p>

<p>
Some meetups use <a href="https://meet.jit.si/">meet.jit.si</a>, Zoom, or Google
Meet, but some are more comfortable on a
self-hosted service using free software. I help by
running a <a href="https://sachachua.com/blog/2025/01/scaling-a-bigbluebutton-server-down-to-a-1-gb-node-between-uses/">BigBlueButton web conferencing server</a>
that I can now automatically scale up and down on
a schedule, so the base cost is about 60 USD/year.
Scaling it up for each meetup costs about USD 0.43
for a 6-hour span. It's pretty automated now,
which is good because I tend to forget things that
are scheduled for specific dates. My schedule
still hasn't settled down enough for me to host
meetups, but I like to drop by once in a while.
</p>

<p>
<b>Yearly:</b> <a href="https://emacsconf.org">EmacsConf</a> is the one big project I like
to work on. It's completely online. It's more of a
friendly get-together than a formal conference. I
have fun trying to fit as many proposed talks as
possible into the schedule. We nudge speakers to
send us recorded presentations of 5-20 minutes
(sometimes longer), although they can share live
if they want to. A number of volunteers help us
caption the videos. Each presentation is followed
by Q&amp;A over web conference, text chat, and/or
collaborative document. Other volunteers handle
checking in speakers and hosting the Q&amp;A sessions.
</p>

<p>
It's a lot of fun for surprisingly little money.
For the two-day conference itself, the <a href="https://sachachua.com/blog/2024/12/emacsconf-2024-notes/">website
hosting cost for EmacsConf 2024</a> was about USD 56
and our setup was able to handle 400 viewers
online (107 max simultaneous users in various web
conferences).
</p>

<p>
EmacsConf takes more time. For me, it's about 1.5
hours a day for 4 months, but I think mostly
that's because I have so much fun figuring out how
to <a href="https://sachachua.com/blog/category/emacsconf">automate things</a> and because I help with the
captions. Lots of other people put time into
preparing presentations, hosting Q&amp;A,
participating, etc. It's worth it, though.
</p>

<p>
I like doing this because it's a great excuse to
nudge people to get cool stuff out of their head
and into something they can share with other
people, and it helps people connect with other
people who are interested in the same things. Some
Q&amp;A sessions have run for hours and turned into
ongoing collaborations. I like turning videos into
captions and searchable text because I still don't
have the time/patience to actually watch videos,
so it's nice to be able to search. And it's
wonderful gathering lots of people into the same
virtual room and seeing the kind of enthusiasm and
energy they share.
</p>

<p>
So yeah, community plumbing turns out to be pretty
enjoyable. If this resonates with you, maybe you
might want to see if your small web community
could use a blog aggregator or a newsletter.
Doesn't have to be anything fancy. You could start
with a list of interesting links you've come
across. I'm curious about what other people do in
their communities to get ideas flowing!
</p>

<p>
Related: <a href="https://sachachua.com/blog/2024/02/2024-02-04-yay-emacs-community-plumbing-streaming-setup-emacs-news-highlights-transcript-export/">the community plumbing section of my blog post / livestream braindump</a>.</p>
<div><a href="https://sachachua.com/blog/2025/05/working-on-the-plumbing-in-a-small-web-community/index.org">View org source for this post</a></div><p>You can <a href="https://social.sachachua.com/@sacha/statuses/01JWMSXZRMX7WS9XSGB20C5JK8" target="_blank" rel="noopener noreferrer">comment on Mastodon</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2025%2F05%2Fworking-on-the-plumbing-in-a-small-web-community%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Adding subheadings and sketches to my blog page navigation</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2025/04/adding-subheadings-and-sketches-to-my-blog-page-navigation/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2025-04-04T13:52:18Z</updated>
    <published>2025-04-03T17:56:09Z</published>
    <category term="11ty" />
<category term="blogging" />
		<id>https://sachachua.com/blog/2025/04/adding-subheadings-and-sketches-to-my-blog-page-navigation/</id>
		<content type="html"><![CDATA[<div class="update" id="orgebcac51">
<p>
<span class="timestamp-wrapper"><span class="timestamp">[2025-04-04 Fri]</span></span>: Fixed link to onThisPage.cjs. Thanks to John Rakestraw for pointing it out!
</p>

</div>

<div class="assumed_audience" id="org81e1a06">
<p>
Assumed audience:
</p>
<ul class="org-ul">
<li>My future self, when I'm trying to figure out where to change things if I want to implement something similar</li>
<li>People who like tweaking their blog's CSS, especially if they also use Org Mode or 11ty</li>
</ul>

</div>

<p>
Headings help us make sense of longer blog posts.
Heading links are like signposts letting you know
what's ahead and where you can take a shortcut to
get to what you're interested in.
</p>

<p>
Headings are useful for me too. Sometimes I browse
my blog and come across things I've completely
forgotten writing about, so the headings can help
me remember without having to reread long posts.
If I use headings more often, I might be able to
work with <a href="https://sachachua.com/blog/2025/03/playing-with-chunk-size-when-writing/">bigger chunks of thoughts</a>. If I can work
with bigger chunks of thoughts, then maybe I can
think about more things that are hard to fit
within the limits of my working memory. Making
headings more navigable also means I might not
have to worry about the tangents I go on and the
number of different thoughts I try to smoosh
together, if people can jump straight to the parts
that sound relevant to them.
</p>

<p>
I particularly like the way Karthik uses a sticky
table of contents for long blog posts like <a href="https://karthinks.com/software/emacs-window-management-almanac/">The
Emacs Window Management Almanac | Karthinks</a>. I
also like the way <a href="https://sphinx-rtd-theme.readthedocs.io/">the Read the Docs Sphinx Theme</a>
displays a nested table of contents on the left
side on wide screens. I use <a href="https://github.com/fniessen/org-html-themes">org-html-themes</a> to
export Org Mode files with that theme when I want
to be fancy, like <a href="https://sachachua.com/dotemacs">my Emacs configuration</a> (usually
works, although sometimes my config is broken).
</p>

<p>
The last time I <a href="https://sachachua.com/blog/2024/11/thinking-about-webpage-margins/">tinkered with my webpage margins</a>,
I put my "On this page" list on the left side and
the blog post headings (if any) on the right side,
mostly because it was easy to do. I just changed
the margin and float attributes of the element
with the subheadings. I'd like to clear up more
space for potential <a href="https://gwern.net/sidenote">sidenotes</a> or doodles, though.
This time, I experimented with nesting the blog
navigation inside the "On this page" navigation on
the left side.
</p>


<figure id="org4166041">
<img src="https://sachachua.com/blog/2025/04/adding-subheadings-and-sketches-to-my-blog-page-navigation/2025-04-02_14-04-30.png" alt="2025-04-02_14-04-30.png">

<figcaption><span class="figure-number">Figure 1: </span>A screenshot of my blog showing the nested links</figcaption>
</figure>

<p>
Here's how I did it:
</p>
<div id="outline-container-adding-subheadings-and-sketches-to-my-blog-page-navigation-org-mode-where-i-start-writing" class="outline-3">
<h3 id="adding-subheadings-and-sketches-to-my-blog-page-navigation-org-mode-where-i-start-writing">Org Mode: where I start writing</h3>
<div class="outline-text-3" id="text-adding-subheadings-and-sketches-to-my-blog-page-navigation-org-mode-where-i-start-writing">
<p>
I use Org Mode's table of contents directive to
include a table of contents in blog posts. I wrap
it inside a <code>sticky-toc</code> block to indicate when I
want it to be part of the sticky table of contents
on my blog. In Org Mode, the syntax looks like
this:
</p>


<div class="org-src-container">
<pre class="src src-org"><span class="org-org-block-begin-line">#+begin_sticky-toc</span>
#+TOC: headlines 2 local
<span class="org-org-block-end-line">#+end_sticky-toc</span>
</pre>
</div>


<p>
I put it in a <a href="https://joaotavora.github.io/yasnippet/">yasnippet</a> so that I don't have to
remember it. I just type <code>tocs</code> (for TOC, sticky)
and then press <code>TAB</code> to complete it.
</p>
</div>
</div>
<div id="outline-container-adding-subheadings-and-sketches-to-my-blog-page-navigation-11ty-static-site-generator-on-this-page" class="outline-3">
<h3 id="adding-subheadings-and-sketches-to-my-blog-page-navigation-11ty-static-site-generator-on-this-page">11ty static site generator: on this page</h3>
<div class="outline-text-3" id="text-adding-subheadings-and-sketches-to-my-blog-page-navigation-11ty-static-site-generator-on-this-page">
<p>
After exporting individual HTML files from Org
Mode, I turn them into my blog using the <a href="https://www.11ty.dev/">11ty</a>
static site generator. To simplify my archive
pages, I have an <a href="https://github.com/sachac/eleventy-blog-setup/blob/master/_includes/shortcodes/onThisPage.cjs"><code>onThisPage</code></a> shortcode which
lists the posts on that page. I changed it to
include the <code>sticky-toc</code> contents from the items'
<code>templateContent</code> attributes.
</p>


<div class="org-src-container">
<pre class="src src-js"><span class="org-keyword">const</span> { JSDOM } = require(<span class="org-string">'jsdom'</span>);

module.exports = <span class="org-keyword">function</span> (<span class="org-variable-name">eleventyConfig</span>) {
  <span class="org-keyword">function</span> <span class="org-function-name">formatPostLine</span>(<span class="org-variable-name">item</span>, <span class="org-variable-name">index</span>) {
    <span class="org-keyword">let</span> <span class="org-variable-name">subtoc</span> = <span class="org-string">''</span>;
    <span class="org-keyword">if</span> (item.templateContent?.match(<span class="org-string">/sticky-toc/</span>)) {
      <span class="org-keyword">const</span> <span class="org-variable-name">doc</span> = <span class="org-keyword">new</span> <span class="org-type">JSDOM</span>(item.templateContent).window.document;
      <span class="org-keyword">const</span> <span class="org-variable-name">sub</span> = doc.querySelector(<span class="org-string">'.sticky-toc ul, .sticky-toc div, .sticky-toc-after-scrolling div'</span>);
      <span class="org-keyword">if</span> (sub) {
        <span class="org-keyword">if</span> (sub.querySelector(<span class="org-string">'.panzoom'</span>)) {
          console.log(<span class="org-string">'remove panzoom'</span>);
          sub.querySelector(<span class="org-string">'.panzoom'</span>).classList.remove(<span class="org-string">'panzoom'</span>);  <span class="org-comment-delimiter">// </span><span class="org-comment">don't do panzoom for now</span>
        }
        sub.classList.remove(<span class="org-string">'panzoom'</span>);
        subtoc = sub.outerHTML;
      }
    }
    <span class="org-keyword">return</span> <span class="org-string">`&lt;li&gt;&lt;a class="toc-link" data-index="index${index}" href="${item.url}"&gt;${item.data.title}&lt;/a&gt;${subtoc}&lt;/li&gt;`</span>;
  }
  eleventyConfig.addShortcode(<span class="org-string">'onThisPage'</span>, <span class="org-keyword">function</span> (<span class="org-variable-name">list</span>) {
    <span class="org-keyword">return</span> <span class="org-string">`&lt;nav class="on-this-page"&gt;</span>
<span class="org-string">On this page:</span>
<span class="org-string">&lt;ul&gt;</span>
<span class="org-string">${list.map(formatPostLine).join("\n")}</span>
<span class="org-string">&lt;/ul&gt;</span>
<span class="org-string">&lt;/nav&gt;`</span>;
  });
};
</pre>
</div>


<p>
And then there's a bunch of CSS in <a href="https://github.com/sachac/eleventy-blog-setup/blob/master/assets/css/style.css">assets/css/style.css</a>:
</p>

<p>
</p><details class="code-details" style="padding: 1em;
                 border-radius: 15px;
                 font-size: 0.9em;
                 box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;">
                  <summary><strong>CSS</strong></summary>

<div class="org-src-container">
<pre class="src src-css"><span class="org-comment-delimiter">/* </span><span class="org-comment">tables of contents</span><span class="org-comment-delimiter"> */</span>
<span class="org-css-selector">.on-this-page &gt; ul &gt; li &gt; ul, .on-this-page &gt; ul &gt; li &gt; div</span> { <span class="org-css-property">display</span>: none }

<span class="org-builtin">@media</span> only screen and (width &gt;= 95em) {
    <span class="org-css-selector">html, body</span> { <span class="org-css-property">overflow-x</span>: unset; }

    <span class="org-css-selector">.sticky-toc, .sticky-left, .sticky-right</span> {
        <span class="org-css-property">font-size</span>: var(<span class="org-variable-name">&#45;&#45;fs-sm</span>);
        <span class="org-css-property">width</span>: calc((100vw - var(<span class="org-variable-name">&#45;&#45;body-max-width</span>) - 5rem)/2);
        <span class="org-css-property">position</span>: sticky;
        <span class="org-css-property">max-height</span>: calc(100vh - 2rem);
        <span class="org-css-property">overflow-y</span>: auto;
        <span class="org-css-property">scroll-behavior</span>: smooth;
        <span class="org-css-property">background</span>: var(<span class="org-variable-name">&#45;&#45;modus-bg-main</span>);
        <span class="org-css-property">top</span>: 0;
        <span class="org-css-property">padding</span>: 1rem;
    }

    <span class="org-css-selector">article .sticky-toc</span> {
        <span class="org-css-property">display</span>: none
    }

    <span class="org-css-selector">.single-post article .sticky-toc</span> {
        <span class="org-css-property">display</span>: block;
    }

    <span class="org-css-selector">.sticky-toc, .sticky-left, .single-post article .sticky-toc</span> {
        <span class="org-css-property">margin-left</span>: calc((-100vw + var(<span class="org-variable-name">&#45;&#45;body-max-width</span>))/2);
        <span class="org-css-property">float</span>: left;
    }

    <span class="org-css-selector">.sticky-right</span> {
        <span class="org-css-property">margin-right</span>: calc((-100vw + var(<span class="org-variable-name">&#45;&#45;body-max-width</span>))/2);
        <span class="org-css-property">float</span>: right;
    }

    <span class="org-comment-delimiter">/* </span><span class="org-comment">Hide the TOCs for non-active posts, but only if JS is enabled</span><span class="org-comment-delimiter"> */</span>
    <span class="org-css-selector">.js .on-this-page &gt; ul &gt; li &gt; ul, .js .on-this-page &gt; ul &gt; li &gt; div</span> { <span class="org-css-property">display</span>: none }
    <span class="org-css-selector">.on-this-page &gt; ul &gt; li.post-active &gt; ul, .on-this-page &gt; ul &gt; li.post-active &gt; div</span> { <span class="org-css-property">display</span>: block }

    <span class="org-css-selector">.active</span> { <span class="org-css-property">background-color</span>: var(<span class="org-variable-name">&#45;&#45;modus-bg-tab-bar</span>) }

    <span class="org-css-selector">.sticky-toc svg .active rect</span> {
        <span class="org-css-property">fill</span>: var(<span class="org-variable-name">&#45;&#45;modus-bg-tab-bar</span>) <span class="org-builtin">!important</span>;
        <span class="org-css-property">fill-opacity</span>: 1 <span class="org-builtin">!important</span>;
        <span class="org-css-property">mix-blend-mode</span>: darken;
        <span class="org-css-property">stroke-dash-array</span>: unset <span class="org-builtin">!important</span>;
        <span class="org-css-property">stroke-width</span>: 4px;
    }

    <span class="org-css-selector">.link-to-nonsticky-toc</span> {
        <span class="org-css-property">display</span>: none
    }
}


</pre>
</div>




</details>

<p></p>

<p>
I also have some Javascript to highlight the active post and show the subheadings for it in <a href="https://github.com/sachac/eleventy-blog-setup/blob/master/assets/js/misc.js">assets/js/misc.js</a>.
</p>

<p>
</p><details class="code-details" style="padding: 1em;
                 border-radius: 15px;
                 font-size: 0.9em;
                 box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;">
                  <summary><strong>Javascript</strong></summary>

<div class="org-src-container">
<pre class="src src-js"><span class="org-comment-delimiter">/* </span><span class="org-comment">Table of contents</span><span class="org-comment-delimiter"> */</span>

<span class="org-keyword">function</span> <span class="org-function-name">stickyTocAfterScrolling</span>() {
  <span class="org-keyword">const</span> <span class="org-variable-name">elements</span> = document.querySelectorAll(<span class="org-string">'.single-post .sticky-toc-after-scrolling'</span>);
  <span class="org-keyword">let</span> <span class="org-variable-name">lastScroll</span> = window.scrollY;

  elements.forEach(element =&gt; {
    <span class="org-keyword">const</span> <span class="org-variable-name">clone</span> = element.cloneNode(<span class="org-constant">true</span>);
    clone.setAttribute(<span class="org-string">'class'</span>, <span class="org-string">'sticky-toc'</span>);
    clone.querySelector(<span class="org-string">'.panzoom'</span>)?.classList.remove(<span class="org-string">'panzoom'</span>);
    element.parentNode.insertBefore(clone, element.nextSibling);
  });

  <span class="org-keyword">const</span> <span class="org-variable-name">observer</span> = <span class="org-keyword">new</span> <span class="org-type">IntersectionObserver</span>(
    (entries) =&gt; {
      <span class="org-keyword">const</span> <span class="org-variable-name">currentScroll</span> = window.scrollY;
      <span class="org-keyword">const</span> <span class="org-variable-name">scrollingDown</span> = currentScroll &gt; lastScroll;
      lastScroll = currentScroll;

      entries.forEach(entry =&gt; {
        <span class="org-keyword">const</span> <span class="org-variable-name">element</span> = entry.target;
        <span class="org-keyword">const</span> <span class="org-variable-name">clone</span> = cloneMap.get(element);

        <span class="org-keyword">if</span> (!entry.isIntersecting &amp;&amp; scrollingDown) {
          clone.setAttribute(<span class="org-string">'class'</span>, <span class="org-string">'sticky-toc'</span>);
          clone.style.display = <span class="org-string">'block'</span>;
        } <span class="org-keyword">else</span> <span class="org-keyword">if</span> (entry.isIntersecting &amp;&amp; !scrollingDown) {
          element.style.visibility = <span class="org-string">'visible'</span>;
          clone.style.display = <span class="org-string">'none'</span>;
        }
      });
    },
    {
      root: <span class="org-constant">null</span>,
      threshold: 0,
      rootMargin: <span class="org-string">'-10px 0px 0px 0px'</span>
    }
  );

  elements.forEach(element =&gt; {
    observer.observe(element);
  });

  window.addEventListener(<span class="org-string">'resize'</span>, () =&gt; {
    elements.forEach(element =&gt; {
      <span class="org-keyword">const</span> <span class="org-variable-name">clone</span> = cloneMap.get(element);
      <span class="org-keyword">if</span> (clone.style.display != <span class="org-string">'none'</span>) {
        <span class="org-comment-delimiter">// </span><span class="org-comment">reset didn't seem to work</span>
        svgPanZoom(clone.querySelector(<span class="org-string">'svg'</span>)).destroy();
        addPanZoomToElement(clone.querySelector(<span class="org-string">'svg'</span>));
      }
    });
  }, { passive: <span class="org-constant">true</span> });
}

stickyTocAfterScrolling();

<span class="org-keyword">function</span> <span class="org-function-name">scrollToActiveTocLink</span>() {
  <span class="org-keyword">const</span> <span class="org-variable-name">activeLink</span> = document.querySelector(<span class="org-string">'.sticky-toc .active'</span>);
  <span class="org-keyword">const</span> <span class="org-variable-name">tocContainer</span> = document.querySelector(<span class="org-string">'.sticky-toc'</span>);
  <span class="org-keyword">if</span> (!activeLink || !tocContainer) <span class="org-keyword">return</span>;
  <span class="org-keyword">const</span> <span class="org-variable-name">tocRect</span> = tocContainer.getBoundingClientRect();
  <span class="org-keyword">const</span> <span class="org-variable-name">linkRect</span> = activeLink.getBoundingClientRect();
  <span class="org-keyword">if</span> (linkRect.top &lt; tocRect.top || linkRect.bottom &gt; tocRect.bottom) {
    <span class="org-keyword">const</span> <span class="org-variable-name">scrollPosition</span> = linkRect.top + tocContainer.scrollTop -
                          (tocRect.height / 2) + (linkRect.height / 2);
    tocContainer.scrollTo({
      top: scrollPosition,
      behavior: <span class="org-string">'smooth'</span>
    });
  }
}
<span class="org-keyword">function</span> <span class="org-function-name">getVisibleArticle</span>() {
  <span class="org-keyword">const</span> <span class="org-variable-name">viewportHeight</span> = window.innerHeight || document.documentElement.clientHeight;
  <span class="org-keyword">return</span> [...document.querySelectorAll(<span class="org-string">'article'</span>)].find((article) =&gt; {
    <span class="org-keyword">const</span> <span class="org-variable-name">rect</span> = article.getBoundingClientRect();
    <span class="org-keyword">const</span> <span class="org-variable-name">visibleTop</span> = Math.max(0, rect.top);
    <span class="org-keyword">const</span> <span class="org-variable-name">visibleBottom</span> = Math.min(viewportHeight, rect.bottom);
    <span class="org-keyword">const</span> <span class="org-variable-name">visibleHeight</span> = Math.max(0, visibleBottom - visibleTop);
    <span class="org-keyword">return</span> visibleHeight &gt; 0; <span class="org-comment-delimiter">// </span><span class="org-comment">find the first visible one</span>
  });
}

<span class="org-keyword">function</span> <span class="org-function-name">handleActiveTOCLink</span>() {
  <span class="org-keyword">const</span> <span class="org-variable-name">updateActive</span> = <span class="org-keyword">function</span>(<span class="org-variable-name">links</span>, <span class="org-variable-name">active</span>) {
    <span class="org-keyword">const</span> <span class="org-variable-name">activeFragment</span> = active.includes(<span class="org-string">'#'</span>) ?
          active.substring(active.indexOf(<span class="org-string">'#'</span>)) : <span class="org-string">''</span>;
    links.forEach(link =&gt; {
      <span class="org-keyword">const</span> <span class="org-variable-name">href</span> = link.getAttribute(<span class="org-string">'href'</span>);
      <span class="org-keyword">if</span> (href.includes(window.location.origin)) {
        link.classList.toggle(<span class="org-string">'active'</span>, href == active)
      } <span class="org-keyword">else</span> <span class="org-keyword">if</span> (href.startsWith(<span class="org-string">'#'</span>)) {
        link.classList.toggle(<span class="org-string">'active'</span>, href == activeFragment);
      }
    });
  };
  <span class="org-keyword">const</span> <span class="org-variable-name">posts</span> = document.querySelectorAll(<span class="org-string">'.post'</span>);
  <span class="org-keyword">const</span> <span class="org-variable-name">tocLinks</span> = document.querySelectorAll(<span class="org-string">'.on-this-page .toc-link'</span>);
  <span class="org-keyword">const</span> <span class="org-variable-name">options</span> = {
    root: <span class="org-constant">null</span>,
    rootMargin: <span class="org-string">'-20% 0px -70% 0px'</span>,
    threshold: 0
  };
  <span class="org-keyword">const</span> <span class="org-variable-name">observer</span> = <span class="org-keyword">new</span> <span class="org-type">IntersectionObserver</span>((entries) =&gt; {
    entries.forEach(entry =&gt; {
      <span class="org-keyword">if</span> (entry.isIntersecting) {
        <span class="org-keyword">const</span> <span class="org-variable-name">id</span> = entry.target.id;
        <span class="org-keyword">const</span> <span class="org-variable-name">link</span> = document.querySelector(<span class="org-string">`.toc-link[data-index="${id}"]`</span>);
        document.querySelectorAll(<span class="org-string">'.sticky-toc .active'</span>).forEach((o) =&gt; o.classList.remove(<span class="org-string">'active'</span>));
        document.querySelectorAll(<span class="org-string">'.post-active'</span>).forEach((o) =&gt; o.classList.remove(<span class="org-string">'post-active'</span>));
        <span class="org-keyword">if</span> (link) {
          link.classList.add(<span class="org-string">'active'</span>);
          <span class="org-keyword">const</span> <span class="org-variable-name">item</span> = link.closest(<span class="org-string">'li'</span>);
          item.classList.add(<span class="org-string">'post-active'</span>);
        }
      }
    });
    scrollToActiveTocLink();
  }, options);
  posts.forEach((post) =&gt; { observer.observe(post); });

  <span class="org-keyword">const</span> <span class="org-variable-name">stickyTocLinks</span> = document.querySelectorAll(<span class="org-string">'article .sticky-toc a, .on-this-page a'</span>);
  <span class="org-keyword">const</span> <span class="org-variable-name">postTocObserver</span> = <span class="org-keyword">new</span> <span class="org-type">IntersectionObserver</span>((entries) =&gt; {
    entries.forEach(entry =&gt; {
      <span class="org-keyword">if</span> (entry.isIntersecting) {
        <span class="org-keyword">const</span> <span class="org-variable-name">id</span> = entry.target.id;
        <span class="org-keyword">const</span> <span class="org-variable-name">url</span> = window.location.origin + window.location.pathname + <span class="org-string">'#'</span> + id.replace(<span class="org-string">/^outline-container-/</span>, <span class="org-string">''</span>);
        updateActive(stickyTocLinks, url);
      }
    });
    scrollToActiveTocLink();
  }, options);

  document.querySelectorAll(<span class="org-string">'article .sticky-toc, article .sticky-toc-after-scrolling'</span>).forEach((toc) =&gt; {
    <span class="org-keyword">const</span> <span class="org-variable-name">post</span> = toc.closest(<span class="org-string">'article'</span>);
    <span class="org-keyword">if</span> (post) {
      post.querySelectorAll(<span class="org-string">'.outline-2, .outline-3'</span>).forEach((section) =&gt; { postTocObserver.observe(section) });
    }
  });
  <span class="org-keyword">const</span> <span class="org-variable-name">visible</span> = getVisibleArticle();
  <span class="org-keyword">const</span> <span class="org-variable-name">id</span> = visible?.id;
  <span class="org-keyword">if</span> (id) {
    <span class="org-keyword">const</span> <span class="org-variable-name">activeLink</span> = document.querySelector(<span class="org-string">`.toc-link[data-index="${id}"]`</span>);
    <span class="org-keyword">if</span> (activeLink) {
      activeLink.classList.add(<span class="org-string">'active'</span>);
      activeLink.closest(<span class="org-string">'li'</span>).classList.add(<span class="org-string">'post-active'</span>);
      scrollToActiveTocLink();
    }
  }
}
handleActiveTOCLink();

</pre>
</div>




</details>

<p></p>
</div>
</div>
<div id="outline-container-adding-subheadings-and-sketches-to-my-blog-page-navigation-i-can-use-a-sketch-as-a-map-too" class="outline-3">
<h3 id="adding-subheadings-and-sketches-to-my-blog-page-navigation-i-can-use-a-sketch-as-a-map-too">I can use a sketch as a map, too</h3>
<div class="outline-text-3" id="text-adding-subheadings-and-sketches-to-my-blog-page-navigation-i-can-use-a-sketch-as-a-map-too">
<p>
I sometimes want to use sketchnotes as overviews,
especially if I've added <a href="https://sachachua.com/blog/2025/01/hyperlinking-svgs/">hyperlinks to them</a>. I
used to make the images show up on the right side,
but now I want them to show up in the left-side
navigation instead. Also, I wanted any links to
headings to automatically get recoloured as I
scroll to that heading.
</p>


<figure id="orga78f37e">
<img src="https://sachachua.com/blog/2025/04/adding-subheadings-and-sketches-to-my-blog-page-navigation/2025-04-02-scrolling-svg.gif" alt="2025-04-02-scrolling-svg.gif">

<figcaption><span class="figure-number">Figure 2: </span>Animated GIF showing how the SVG highlights change as you scroll down</figcaption>
</figure>

<p>
I added a special case to the
<code>handleActiveTOCLink</code> function to handle anchor
hyperlinks (just <code>#anchor</code>) in the SVG. It
probably makes sense to make those absolute URLs,
which means slightly changing my workflows for
hyperlinking SVGs and writing about sketches.
</p>

<p>
So on both the category page (ex: the Hyperlinking
SVGs entry in <a href="https://sachachua.com/blog/category/drawing/">category - drawing</a>, which might have
moved off the first page of results if you're
reading this far in the future) and the
single-post page (ex: <a href="https://sachachua.com/blog/2025/01/hyperlinking-svgs/">Hyperlinking SVGs</a>), there's
a full-sized version of the image in the main blog
post, and then a small copy of it in the margin on
the left. The sidebar copy is probably too small
to read, but it might be enough to get a sense of
spatial relationships, and the links also have
<code>title</code> attributes that are displayed as tooltips
when you hover.
</p>


<figure id="orgc5263b9">
<img src="https://sachachua.com/blog/2025/04/adding-subheadings-and-sketches-to-my-blog-page-navigation/2025-04-03_14-28-48.png" alt="2025-04-03_14-28-48.png">

<figcaption><span class="figure-number">Figure 3: </span>Screenshot of small image in sidebar on the single post page</figcaption>
</figure>

<p>
I use Javascript to duplicate the image and make a
small, sticky version because I haven't quite
figured out how to properly make it sticky when
off-screen with just CSS. Even my JS feels a
little tangled. Maybe this would be a good excuse
to learn about web components; someone's probably
figured out something polished.
</p>

<p>
I'm curious about using more drawings to anchor my
thinking and structure my blog posts.
</p>
</div>
</div>
<div id="outline-container-adding-subheadings-and-sketches-to-my-blog-page-navigation-progressive-enhancement" class="outline-3">
<h3 id="adding-subheadings-and-sketches-to-my-blog-page-navigation-progressive-enhancement">Progressive enhancement</h3>
<div class="outline-text-3" id="text-adding-subheadings-and-sketches-to-my-blog-page-navigation-progressive-enhancement">
<p>
Some people read my blog using <a href="https://www.gnu.org/software/emacs/manual/html_mono/eww.html">EWW</a> (the Emacs Web
Wowser, of course), so I want my blog to be
reasonable even without CSS and JS.
</p>

<p>
A number of people read my blog without Javascript
enabled. I installed the <a href="https://addons.mozilla.org/en-US/firefox/addon/script-switch/">Firefox extension Script
Switch</a> so that I can test my blog with and without
Javascript whenever I remember.
</p>

<p>
I sometimes look up my blog posts on my phone and
there's no space for any of this fanciness there,
so it'll only kick in on large screens. My CSS
file is littered with various breakpoints I've
cargo-culted over the years and I should simplify
it at some point. At the moment, if it looks fine
on my Lenovo P52, I'm happy.
</p>
</div>
</div>
<div id="outline-container-adding-subheadings-and-sketches-to-my-blog-page-navigation-other-ideas-and-next-steps" class="outline-3">
<h3 id="adding-subheadings-and-sketches-to-my-blog-page-navigation-other-ideas-and-next-steps">Other ideas and next steps</h3>
<div class="outline-text-3" id="text-adding-subheadings-and-sketches-to-my-blog-page-navigation-other-ideas-and-next-steps">
<p>
Theoretically, the right margin is now available
for <a href="https://gwern.net/sidenote">sidenotes</a>, so I might be able to look at
<a href="https://github.com/ox-tufte/ox-tufte">ox-tufte</a> and <a href="https://eleventufte.netlify.app/features/">Eleventufte</a> and get something going.
Then I'll have a way to add small notes that are
shorter than a paragraph. Longer tangents can go
in a details/summary element instead, although I
have it on good authority that <a href="https://maggieappleton.com/narrative-essays/#:~:text=He%20taught%20me%20it%20is%20100%25%20okay%20to%20write%20an%20entire%20side%2Dnovel%20in%20your%20footnotes%20if%20you%20need%20to.">one can write at
length in footnotes</a>. I love the footnotes in the
Bartimaeus series, and apparently there are quite
a few books where the <a href="https://reactormag.com/for-the-love-of-footnotes-when-fantasy-gets-extra-nerdy/">footnotes are part of the
storytelling</a>.)
</p>

<p>
It might be nice to let tables extend into the
right sidebar when I know I won't have a doodle
nearby. Incidentally, <a href="https://gwern.net/sidenote">Sidenotes In Web Design ·
Gwern.net</a> uses breadcrumbs in the left sidebar
instead of a table of contents, so there's more
space for tables and sidenotes.
</p>

<p>
I thought about using CSS breakpoints so that on a
medium-sized screen, we can have the left sidebar
even if there's no space for something on the
right. I haven't gotten around to experimenting
with it yet, though. Besides, I don't know yet if
I want to prioritize the stuff I want in the right
sidebar (side notes, doodles) over fairly-static
navigation.
</p>

<p>
As I mentioned, it might be handy to tweak my SVG
linking workflow to use absolute URLs.
</p>

<p>
Sometimes I look up my notes within Emacs, but
surprisingly often, I look them up on the Web.
Navigation isn't just cosmetic. I want to get
better at using my blog as a tool for thought, so
tinkering with layout isn't just window dressing.
It's (very slowly) experimenting with scaffolding
for my brain. Little things can help!</p>
</div>
</div>
<p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2025%2F04%2Fadding-subheadings-and-sketches-to-my-blog-page-navigation%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Using Emacs Lisp to batch-demote HTML headings for my static site</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2025/04/using-emacs-lisp-to-batch-demote-html-headings-for-my-static-site/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2025-04-03T17:23:43Z</updated>
    <published>2025-04-03T17:23:43Z</published>
    <category term="blogging" />
<category term="11ty" />
<category term="emacs" />
		<id>https://sachachua.com/blog/2025/04/using-emacs-lisp-to-batch-demote-html-headings-for-my-static-site/</id>
		<content type="html"><![CDATA[<div class="assumed_audience" id="orgb8392f2">
<p>
Assumed audience: People who have lots of HTML
files used as input for a static site generator,
might need to do a batch operation on them, and
are open to doing that with Emacs Lisp. Which
might just be me, but who knows? =)
</p>

</div>

<p>
HTML defines a hierarchy of headings going from
<code>&lt;h1&gt;</code> to <code>&lt;h6&gt;</code>, which comes in especially handy
when people are <a href="https://usability.yale.edu/web-accessibility/articles/headings">navigating with a screenreader</a> or
<a href="https://github.com/alphapapa/org-web-tools">converting web pages to Org Mode</a>. I think search
engines might use them to get a sense of the
page's structure, too. On my blog, the hierarchy
usually goes like this:
</p>

<ul class="org-ul">
<li><code>&lt;h1&gt;</code>: site title,</li>
<li><code>&lt;h2&gt;</code>: blog post titles, since I put multiple
blog posts on the <a href="https://sachachua.com/blog/">main page</a> and category pages
(ex: <a href="https://sachachua.com/blog/category/blogging">blogging</a>)</li>
<li><code>&lt;h3&gt;</code>: blog post's subheadings, if any</li>
<li><code>&lt;h4&gt;</code>: I rarely need subsubheadings in my main blog posts, but they're there just in case</li>
</ul>

<p>
While fiddling with my blog's CSS so that I could
try this <a href="https://www.fluid-type-scale.com/calculate?minFontSize=16&amp;minWidth=400&amp;minRatio=1.25&amp;maxFontSize=22&amp;maxWidth=1280&amp;maxRatio=1.333&amp;steps=sm%2Cbase%2Cmd%2Clg%2Cxl%2Cxxl%2Cxxxl&amp;baseStep=base&amp;prefix=fs&amp;useContainerWidth=false&amp;includeFallbacks=true&amp;useRems=true&amp;remValue=16&amp;decimals=2&amp;previewFont=Inter&amp;previewText=Almost+before+we+knew+it%2C+we+had+left+the+ground&amp;previewWidth=1280">fluid type scale</a>, I realized that the
subheadings in my exported blog entries started at
<code>&lt;h2&gt;</code> instead of <code>&lt;h3&gt;</code>. This meant that the outline was this:
</p>

<ul class="org-ul">
<li>Site title
<ul class="org-ul">
<li>Blog post 1</li>
<li>Subheading 1</li>
<li>Subheading 2</li>
<li>Blog post 2</li>
<li>Subheading 1</li>
<li>Subheading 2</li>
<li>Blog post 3</li>
</ul></li>
</ul>

<p>
I wanted the outline to be this:
</p>

<ul class="org-ul">
<li>Site title
<ul class="org-ul">
<li>Blog post 1
<ul class="org-ul">
<li>Subheading 1</li>
<li>Subheading 2</li>
</ul></li>
<li>Blog post 2
<ul class="org-ul">
<li>Subheading 1</li>
<li>Subheading 2</li>
</ul></li>
<li>Blog post 3</li>
</ul></li>
</ul>

<p>
This was because I hadn't changed
<code>org-html-toplevel-hlevel</code> during my 11ty export
process. To solve this for new posts, I added a
new option <code>org-11ty-toplevel-hlevel</code> that
defaults to 3 in <a href="https://github.com/sachac/ox-11ty/blob/master/ox-11ty.el">ox-11ty.el</a>, re-exported
one of my long blog posts to test it, and
confirmed that my headings now started at <code>&lt;h3&gt;</code>.
</p>

<p>
I still had all my old HTML files with the wrong
levels of headings. I wrote some Emacs Lisp to
shift the headings downwards (h5 to h6, h4 to h5,
h3 to h4, h2 to h3) in a file if it had an <code>&lt;h2&gt;</code>
in it. Regular expressions are usually not a good
idea when it comes to HTML because there might be
exceptions, but I figured it was a pretty small
and low-risk change, so I decided not to use the
full XML/DOM parsing functions. I saved all the
blog posts under version control just in case I
messed things up. Here's my function:
</p>


<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">defun</span> <span class="org-function-name">my-html-shift-headings</span> (filename)
  <span class="org-doc">"Shift heading tags in FILENAME."</span>
  (<span class="org-keyword">interactive</span> <span class="org-string">"FFile: "</span>)
  (<span class="org-keyword">let</span> ((case-fold-search t)) <span class="org-comment-delimiter">; </span><span class="org-comment">make the search case-insensitive</span>
    (<span class="org-keyword">with-temp-buffer</span>
      (insert-file-contents filename)
      (goto-char (point-min))
      <span class="org-comment-delimiter">;; </span><span class="org-comment">Only modify the files where we have an h2</span>
      (<span class="org-keyword">when</span> (<span class="org-keyword">or</span> (search-forward <span class="org-string">"&lt;h2"</span> nil t)
                (search-forward <span class="org-string">"&lt;/h2&gt;"</span> nil t))
        (goto-char (point-min))
        <span class="org-comment-delimiter">;; </span><span class="org-comment">Handle both opening and closing tags</span>
        (<span class="org-keyword">while</span> (re-search-forward <span class="org-string">"&lt;</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">/</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">?h</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">[2-5]</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">\\&gt;"</span> nil t)
          (<span class="org-keyword">let*</span> ((closing-tag (match-string 1))
                 (heading-level (string-to-number (match-string 2)))
                 (new-level (1+ heading-level)))
            (replace-match (concat <span class="org-string">"&lt;"</span> closing-tag <span class="org-string">"h"</span> (number-to-string new-level)))))
        (write-file filename)
        filename))))
</pre>
</div>


<p>
Running it on all the source HTML files in
specific subdirectories was easy with
<code>directory-files-recursively</code>.
</p>


<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">dolist</span> (dir <span class="org-highlight-quoted-quote">'</span>(<span class="org-string">"~/proj/static-blog/blog"</span>
               <span class="org-string">"~/proj/static-blog/content"</span>))
  (mapc <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">my-html-shift-headings</span>
        (directory-files-recursively
         dir
         <span class="org-string">"\\.html\\'"</span>)))
</pre>
</div>


<p>
Then I could just rebuild my blog and get all the
right heading levels. Spot-checks with Inspect
Element show that the headings now have the right
tags, and <code>org-web-tools-read-url-as-org</code> now
picks up the right hierarchy for the page.
</p>

<p>
Correcting the input files was easier and more
efficient than modifying my 11ty template engine
to shift the heading levels whenever I build my
site (probably by defining a <a href="https://www.11ty.dev/docs/config-preprocessors/">preprocessor</a>). I
could've written a NodeJS script to do that kind
of file manipulation, but writing it in Emacs Lisp
matched how I might think of doing it
interactively. Using Emacs Lisp was also easy to
test on one or two files, check the list of files
matched by <code>directory-files-recursively</code>, and then
run it on everything.
</p>

<p>
Going forward, the new <code>org-11ty-toplevel-hlevel</code>
variable should properly modify the behaviour of
Org's HTML export to get the headings at the right
level. We'll see!</p>
<p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2025%2F04%2Fusing-emacs-lisp-to-batch-demote-html-headings-for-my-static-site%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Moving 18 years of comments out of Disqus and into my 11ty static site</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2025/03/moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2025-03-30T13:11:08Z</updated>
    <published>2025-03-30T13:11:08Z</published>
    <category term="11ty" />
<category term="blogging" />
		<id>https://sachachua.com/blog/2025/03/moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site/</id>
		<content type="html"><![CDATA[<div class="sticky-toc" id="org78e19a3">
<div id="text-table-of-contents" role="doc-toc">
<ul>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-exploring-my-disqus-xml-with-xq-org-babel-and-seaborn">Exploring my disqus.xml with xq, Org Babel, and seaborn</a></li>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-deleting-spam-comments-via-the-disqus-web-interface-and-spookfox">Deleting spam comments via the Disqus web interface and Spookfox</a></li>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-modifying-eleventy-import-disqus-for-my-site">Modifying eleventy-import-disqus for my site</a></li>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-next-steps">Next steps</a></li>
</ul>
</div>

</div>

<div class="assumed_audience" id="orgdecdaa5">
<p>
<a href="https://maggieappleton.com/assumed-audience/">Assumed audience</a>: Technical bloggers who like:
</p>
<ul class="org-ul">
<li>static site generators: this post is about moving more things into my SSG</li>
<li>XML: check out the mention of xq, which offers a jq-like interface</li>
<li>or Org Mode: some notes here about Org Babel source blocks and graphing</li>
</ul>

</div>

<p>
I've been thinking of getting rid of the <a href="https://disqus.com/">Disqus</a>
blog commenting system for a while. I used to use
it in the hopes that it would handle spam
filtering and the "someone has replied to your
comment" notification for me. Getting rid of
Disqus means one less thing that needs Javascript,
one less thing that tracks people in ways we don't
want, one less thing that shows ads and wants to
sell our attention. Comments are rare enough these
days, so I think I can handle e-mailing people
when there are replies.
</p>

<p>
There are plenty of alternative commenting systems
to choose from. <a href="https://gitlab.com/comentario/comentario">Comentario</a> and <a href="https://isso-comments.de/">Isso</a> are
self-hosted, while <a href="https://commento.io/pricing">Commento</a> (USD 10/month) and
<a href="https://talk.hyvor.com/pricing">Hyvor Talk</a> (12 euro/month) are services.
<a href="https://utteranc.es/">Utterances</a> uses Github issues, which is probably
not something I'll try as quite a few people in
the Emacs community are philosophically opposed to
Github. Along those lines, if I can find something
that works without Javascript, that would be even
better.
</p>

<p>
I could spend a few years trying to figure out
which system I might like in terms of user
interface, integration, and spam-filtering, but
for now, I want to:
</p>
<ul class="org-ul">
<li>remove Disqus</li>
<li>keep the comments, since they add a lot to the page (ex: the conversation on <a href="https://sachachua.com/blog/2021/01/a-list-of-sharks-that-are-obligate-ram-ventilators/">A list of sharks that are obligate ram ventilators</a>)</li>
</ul>

<p>
Fortunately, there's <a href="https://github.com/11ty/eleventy-import-disqus">11ty/eleventy-import-disqus</a> (<a href="https://www.zachleat.com/web/disqus-import/">see zachleat's blog post: Import your Disqus Comments to Eleventy</a>)
</p>
<div id="outline-container-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-exploring-my-disqus-xml-with-xq-org-babel-and-seaborn" class="outline-2">
<h3 id="moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-exploring-my-disqus-xml-with-xq-org-babel-and-seaborn">Exploring my disqus.xml with xq, Org Babel, and seaborn</h3>
<div class="outline-text-2" id="text-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-exploring-my-disqus-xml-with-xq-org-babel-and-seaborn">
<p>
One challenge: there are a <i>lot</i> of comments. How
many? I got curious about analyzing the XML, and
then of course I wanted to do that from Emacs. I
used <code>pipx install yq</code> to install <a href="https://github.com/mikefarah/yq">yq</a> so that I
could use the xq tool to <a href="https://www.ashbyhq.com/blog/engineering/jq-and-yq">query the XML</a>, much like
<a href="https://jqlang.org/">jq</a> works.
</p>

<p>
My uncompressed Disqus XML export was 28MB. I spent
some time deleting spam comments through the web
interface, which helped with the filtering. I also
deleted some more comments from the XML file as I
noticed them. I needed to change <code>/wp/</code> to <code>/blog/</code>, too.
</p>

<p>
This is how I analyzed the archive for non-deleted
posts, uniquified based on message. I'll include
the full Org source of that block (including the
header lines) in my blog post so that you can see
how I call it later.
</p>


<div class="org-src-container">
<pre class="src src-org"><span class="org-org-meta-line">#+NAME: analyze-disqus</span>
<span class="org-org-block-begin-line">#+begin_src shell :var rest="| length | \"\\(.) unique comments\"" :exports results</span>
<span class="org-org-block">~/.local/bin/xq -r </span><span class="org-org-block"><span class="org-string">"[.disqus.post[] |</span></span>
<span class="org-org-block"><span class="org-string">   select(.isDeleted != \"true\" and .message) |</span></span>
<span class="org-org-block"><span class="org-string">   {key: .message, value: .}] |</span></span>
<span class="org-org-block"><span class="org-string">  map(.value) |</span></span>
<span class="org-org-block"><span class="org-string">  unique_by(.message) ${rest}"</span></span><span class="org-org-block"> &lt; disqus.xml</span>
<span class="org-org-block-end-line">#+end_src</span>
</pre>
</div>


<p>
When I evaluate that with <code>C-c C-c</code>, I get:
</p>

<p>
8265 unique comments
</p>

<p>
I was curious about how it broke down by year. Because I named the source code block and used a variable to specify how to process the filtered results earlier, I can call that with a different value.
</p>

<p>
Here's the call in my Org Mode source:
</p>


<div class="org-src-container">
<pre class="src src-org"><span class="org-org-meta-line">#+CALL: analyze-disqus(rest="| map(.createdAt[0:4]) | group_by(.) | map([(.[0]), length]) | reverse | [\"Year\", \"Count\"], .[] | @csv") :results table output :wrap my_details Table of comment count by year</span>
</pre>
</div>


<details class="code-details" style="padding: 1em;
                 border-radius: 15px;
                 font-size: 0.9em;
                 box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;">
                  <summary><strong>Table of comment count by year</strong></summary>
<table>


<colgroup>
<col class="org-right">

<col class="org-right">
</colgroup>
<tbody>
<tr>
<td class="org-right">Year</td>
<td class="org-right">Count</td>
</tr>

<tr>
<td class="org-right">2025</td>
<td class="org-right">26</td>
</tr>

<tr>
<td class="org-right">2024</td>
<td class="org-right">43</td>
</tr>

<tr>
<td class="org-right">2023</td>
<td class="org-right">34</td>
</tr>

<tr>
<td class="org-right">2022</td>
<td class="org-right">40</td>
</tr>

<tr>
<td class="org-right">2021</td>
<td class="org-right">55</td>
</tr>

<tr>
<td class="org-right">2020</td>
<td class="org-right">131</td>
</tr>

<tr>
<td class="org-right">2019</td>
<td class="org-right">107</td>
</tr>

<tr>
<td class="org-right">2018</td>
<td class="org-right">139</td>
</tr>

<tr>
<td class="org-right">2017</td>
<td class="org-right">186</td>
</tr>

<tr>
<td class="org-right">2016</td>
<td class="org-right">196</td>
</tr>

<tr>
<td class="org-right">2015</td>
<td class="org-right">593</td>
</tr>

<tr>
<td class="org-right">2014</td>
<td class="org-right">740</td>
</tr>

<tr>
<td class="org-right">2013</td>
<td class="org-right">960</td>
</tr>

<tr>
<td class="org-right">2012</td>
<td class="org-right">784</td>
</tr>

<tr>
<td class="org-right">2011</td>
<td class="org-right">924</td>
</tr>

<tr>
<td class="org-right">2010</td>
<td class="org-right">966</td>
</tr>

<tr>
<td class="org-right">2009</td>
<td class="org-right">1173</td>
</tr>

<tr>
<td class="org-right">2008</td>
<td class="org-right">1070</td>
</tr>

<tr>
<td class="org-right">2007</td>
<td class="org-right">98</td>
</tr>
</tbody>
</table>


</details>

<p>
I tried fiddling around with <a href="https://orgmode.org/manual/Org-Plot.html">Org's #+PLOT keyword</a>,
but I couldn't figure out how to get the bar graph
the way I wanted it to be. Someday, if I ever
figure that out, I'll definitely save the <a href="http://yummymelon.com/devnull/beautifying-org-plot-with-yasnippet-and-context-menus.html">Gnuplot
setup as a snippet</a>. For now, I visualized it using
<a href="https://seaborn.pydata.org/">seaborn</a> instead.
</p>

<details><summary>Code for graphing comments by year</summary>
<div class="org-src-container">
<pre class="src src-python"><span class="org-keyword">import</span> pandas <span class="org-keyword">as</span> pd
<span class="org-keyword">import</span> seaborn <span class="org-keyword">as</span> sns
<span class="org-keyword">import</span> matplotlib.pyplot <span class="org-keyword">as</span> plt
<span class="org-keyword">import</span> numpy <span class="org-keyword">as</span> np

<span class="org-variable-name">df</span> <span class="org-operator">=</span> pd.DataFrame(data[1:], columns<span class="org-operator">=</span>data[0])
<span class="org-variable-name">df</span>[<span class="org-string">'Count'</span>] <span class="org-operator">=</span> df[<span class="org-string">'Count'</span>].astype(<span class="org-builtin">int</span>)
<span class="org-variable-name">df</span>[<span class="org-string">'Year'</span>] <span class="org-operator">=</span> df[<span class="org-string">'Year'</span>].astype(<span class="org-builtin">int</span>)
<span class="org-variable-name">df</span> <span class="org-operator">=</span> df.sort_values(<span class="org-string">'Year'</span>)
plt.figure(figsize<span class="org-operator">=</span>(12, 6))
<span class="org-variable-name">ax</span> <span class="org-operator">=</span> sns.barplot(x<span class="org-operator">=</span><span class="org-string">'Year'</span>, y<span class="org-operator">=</span><span class="org-string">'Count'</span>, data<span class="org-operator">=</span>df)
plt.title(<span class="org-string">'Comments by Year (2007-2025)'</span>, fontsize<span class="org-operator">=</span>16, fontweight<span class="org-operator">=</span><span class="org-string">'bold'</span>)
plt.xlabel(<span class="org-string">'Year'</span>)
plt.ylabel(<span class="org-string">'Comments'</span>)
plt.xticks(rotation<span class="org-operator">=</span>45)
plt.grid(axis<span class="org-operator">=</span><span class="org-string">'y'</span>)
<span class="org-keyword">for</span> i, v <span class="org-keyword">in</span> <span class="org-builtin">enumerate</span>(df[<span class="org-string">'Count'</span>]):
<span class="org-highlight-indentation"> </span>   ax.text(i, v <span class="org-operator">+</span> 20, <span class="org-builtin">str</span>(v), ha<span class="org-operator">=</span><span class="org-string">'center'</span>, fontsize<span class="org-operator">=</span>9)
plt.tight_layout()
plt.savefig(<span class="org-string">'year_count_plot.svg'</span>)
<span class="org-keyword">return</span> <span class="org-string">'year_count_plot.svg'</span>
</pre>
</div>

</details>


<figure id="org7651eec">
<img src="https://sachachua.com/blog/2025/03/moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site/year_count_plot.svg" alt="year_count_plot.svg" class="org-svg" data-link="t">

</figure>

<p>
Ooooooh, I can probably cross-reference this with
the number of posts from my <a href="https://sachachua.com/blog/all/index.json">/blog/all/index.json</a> file.
I used <a href="https://claude.ai">Claude AI</a>'s help to come up with the code below, since merging data and plotting them nicely is still challenging for me. Now that I have the example, though, maybe I can do other graphs more easily. (This looks like a related tutorial on <a href="https://www.geeksforgeeks.org/combining-barplots-and-lineplots-with-different-y-axes-a-technical-guide/">combining barplots and lineplots</a>.)
</p>

<details><summary>Code for graphing</summary>
<div class="org-src-container">
<pre class="src src-python"><span class="org-keyword">import</span> pandas <span class="org-keyword">as</span> pd
<span class="org-keyword">import</span> seaborn <span class="org-keyword">as</span> sns
<span class="org-keyword">import</span> matplotlib.pyplot <span class="org-keyword">as</span> plt
<span class="org-keyword">import</span> numpy <span class="org-keyword">as</span> np
<span class="org-keyword">import</span> json
<span class="org-keyword">from</span> matplotlib.ticker <span class="org-keyword">import</span> FuncFormatter
<span class="org-keyword">from</span> datetime <span class="org-keyword">import</span> datetime

<span class="org-keyword">with</span> <span class="org-builtin">open</span>(<span class="org-string">'/home/sacha/proj/static-blog/_site/blog/all/index.json'</span>, <span class="org-string">'r'</span>) <span class="org-keyword">as</span> f:
<span class="org-highlight-indentation"> </span>   <span class="org-variable-name">posts_data</span> <span class="org-operator">=</span> json.load(f)

<span class="org-comment-delimiter"># </span><span class="org-comment">Process post data</span>
<span class="org-variable-name">posts_df</span> <span class="org-operator">=</span> pd.DataFrame(posts_data)
<span class="org-variable-name">posts_df</span>[<span class="org-string">'Year'</span>] <span class="org-operator">=</span> pd.to_datetime(posts_df[<span class="org-string">'date'</span>]).dt.year
<span class="org-variable-name">post_counts</span> <span class="org-operator">=</span> posts_df.groupby(<span class="org-string">'Year'</span>).size().reset_index(name<span class="org-operator">=</span><span class="org-string">'post_count'</span>)

<span class="org-comment-delimiter"># </span><span class="org-comment">Convert to DataFrame</span>
<span class="org-variable-name">comments_df</span> <span class="org-operator">=</span> pd.DataFrame(comment_data[1:], columns<span class="org-operator">=</span>comment_data[0])
<span class="org-variable-name">comments_df</span>[<span class="org-string">'Count'</span>] <span class="org-operator">=</span> comments_df[<span class="org-string">'Count'</span>].astype(<span class="org-builtin">int</span>)
<span class="org-variable-name">comments_df</span>[<span class="org-string">'Year'</span>] <span class="org-operator">=</span> comments_df[<span class="org-string">'Year'</span>].astype(<span class="org-builtin">int</span>)

<span class="org-comment-delimiter"># </span><span class="org-comment">Merge the two dataframes</span>
<span class="org-variable-name">merged_df</span> <span class="org-operator">=</span> pd.merge(post_counts, comments_df, on<span class="org-operator">=</span><span class="org-string">'Year'</span>, how<span class="org-operator">=</span><span class="org-string">'outer'</span>).fillna(0)
<span class="org-variable-name">merged_df</span> <span class="org-operator">=</span> merged_df.sort_values(<span class="org-string">'Year'</span>)

<span class="org-comment-delimiter"># </span><span class="org-comment">Calculate comments per post ratio</span>
<span class="org-variable-name">merged_df</span>[<span class="org-string">'comments_per_post'</span>] <span class="org-operator">=</span> merged_df[<span class="org-string">'Count'</span>] <span class="org-operator">/</span> merged_df[<span class="org-string">'post_count'</span>]
<span class="org-variable-name">merged_df</span>[<span class="org-string">'comments_per_post'</span>] <span class="org-operator">=</span> merged_df[<span class="org-string">'comments_per_post'</span>].replace([np.inf, <span class="org-operator">-</span>np.inf], np.nan).fillna(0)

<span class="org-comment-delimiter"># </span><span class="org-comment">Create a single figure instead of two subplots</span>
<span class="org-variable-name">fig</span>, <span class="org-variable-name">ax1</span> <span class="org-operator">=</span> plt.subplots(figsize<span class="org-operator">=</span>(15, 8))

<span class="org-comment-delimiter"># </span><span class="org-comment">Custom colors</span>
<span class="org-variable-name">post_color</span> <span class="org-operator">=</span> <span class="org-string">"#1f77b4"</span>    <span class="org-comment-delimiter"># </span><span class="org-comment">blue</span>
<span class="org-variable-name">comment_color</span> <span class="org-operator">=</span> <span class="org-string">"#ff7f0e"</span> <span class="org-comment-delimiter"># </span><span class="org-comment">orange</span>
<span class="org-variable-name">ratio_color</span> <span class="org-operator">=</span> <span class="org-string">"#2ca02c"</span>   <span class="org-comment-delimiter"># </span><span class="org-comment">green</span>

<span class="org-comment-delimiter"># </span><span class="org-comment">Setting up x-axis positions</span>
<span class="org-variable-name">x</span> <span class="org-operator">=</span> np.arange(<span class="org-builtin">len</span>(merged_df))
<span class="org-variable-name">width</span> <span class="org-operator">=</span> 0.35

<span class="org-comment-delimiter"># </span><span class="org-comment">Bar charts on first y-axis</span>
<span class="org-variable-name">bars1</span> <span class="org-operator">=</span> ax1.bar(x <span class="org-operator">-</span> width<span class="org-operator">/</span>2, merged_df[<span class="org-string">'post_count'</span>], width, color<span class="org-operator">=</span>post_color, label<span class="org-operator">=</span><span class="org-string">'Posts'</span>)
<span class="org-variable-name">bars2</span> <span class="org-operator">=</span> ax1.bar(x <span class="org-operator">+</span> width<span class="org-operator">/</span>2, merged_df[<span class="org-string">'Count'</span>], width, color<span class="org-operator">=</span>comment_color, label<span class="org-operator">=</span><span class="org-string">'Comments'</span>)
ax1.set_ylabel(<span class="org-string">'Count (Posts &amp; Comments)'</span>, fontsize<span class="org-operator">=</span>12)

<span class="org-comment-delimiter"># </span><span class="org-comment">Add post count values above bars</span>
<span class="org-keyword">for</span> i, bar <span class="org-keyword">in</span> <span class="org-builtin">enumerate</span>(bars1):
<span class="org-highlight-indentation"> </span>   <span class="org-variable-name">height</span> <span class="org-operator">=</span> bar.get_height()
<span class="org-highlight-indentation"> </span>   <span class="org-keyword">if</span> height <span class="org-operator">&gt;</span> 0:
<span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   ax1.text(bar.get_x() <span class="org-operator">+</span> bar.get_width()<span class="org-operator">/</span>2., height <span class="org-operator">+</span> 5,
<span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   f<span class="org-string">'</span>{<span class="org-builtin">int</span>(height)}<span class="org-string">'</span>, ha<span class="org-operator">=</span><span class="org-string">'center'</span>, va<span class="org-operator">=</span><span class="org-string">'bottom'</span>, color<span class="org-operator">=</span>post_color, fontsize<span class="org-operator">=</span>9)

<span class="org-comment-delimiter"># </span><span class="org-comment">Add comment count values above bars</span>
<span class="org-keyword">for</span> i, bar <span class="org-keyword">in</span> <span class="org-builtin">enumerate</span>(bars2):
<span class="org-highlight-indentation"> </span>   <span class="org-variable-name">height</span> <span class="org-operator">=</span> bar.get_height()
<span class="org-highlight-indentation"> </span>   <span class="org-keyword">if</span> height <span class="org-operator">&gt;</span> 20:  <span class="org-comment-delimiter"># </span><span class="org-comment">Only show if there's enough space</span>
<span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   ax1.text(bar.get_x() <span class="org-operator">+</span> bar.get_width()<span class="org-operator">/</span>2., height <span class="org-operator">+</span> 5,
<span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   f<span class="org-string">'</span>{<span class="org-builtin">int</span>(height)}<span class="org-string">'</span>, ha<span class="org-operator">=</span><span class="org-string">'center'</span>, va<span class="org-operator">=</span><span class="org-string">'bottom'</span>, color<span class="org-operator">=</span>comment_color, fontsize<span class="org-operator">=</span>9)

<span class="org-comment-delimiter"># </span><span class="org-comment">Line graph on second y-axis</span>
<span class="org-variable-name">ax2</span> <span class="org-operator">=</span> ax1.twinx()
<span class="org-variable-name">line</span> <span class="org-operator">=</span> ax2.plot(x, merged_df[<span class="org-string">'comments_per_post'</span>], marker<span class="org-operator">=</span><span class="org-string">'o'</span>, color<span class="org-operator">=</span>ratio_color,
<span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span> linewidth<span class="org-operator">=</span>2, label<span class="org-operator">=</span><span class="org-string">'Comments per Post'</span>)
ax2.set_ylabel(<span class="org-string">'Comments per Post'</span>, color<span class="org-operator">=</span>ratio_color, fontsize<span class="org-operator">=</span>12)
ax2.tick_params(axis<span class="org-operator">=</span><span class="org-string">'y'</span>, labelcolor<span class="org-operator">=</span>ratio_color)
ax2.set_ylim(bottom<span class="org-operator">=</span>0)

<span class="org-comment-delimiter"># </span><span class="org-comment">Add ratio values near line points</span>
<span class="org-keyword">for</span> i, ratio <span class="org-keyword">in</span> <span class="org-builtin">enumerate</span>(merged_df[<span class="org-string">'comments_per_post'</span>]):
<span class="org-highlight-indentation"> </span>   <span class="org-keyword">if</span> ratio <span class="org-operator">&gt;</span> 0:
<span class="org-highlight-indentation"> </span>   <span class="org-highlight-indentation"> </span>   ax2.text(i, ratio <span class="org-operator">+</span> 0.2, f<span class="org-string">'</span>{ratio:.1f}<span class="org-string">'</span>, ha<span class="org-operator">=</span><span class="org-string">'center'</span>, color<span class="org-operator">=</span>ratio_color, fontsize<span class="org-operator">=</span>9)

<span class="org-comment-delimiter"># </span><span class="org-comment">Set x-axis labels</span>
ax1.set_xticks(x)
ax1.set_xticklabels(merged_df[<span class="org-string">'Year'</span>], rotation<span class="org-operator">=</span>45)
ax1.set_title(<span class="org-string">'Blog Posts, Comments, and Comments per Post by Year'</span>, fontsize<span class="org-operator">=</span>16, fontweight<span class="org-operator">=</span><span class="org-string">'bold'</span>)
ax1.grid(axis<span class="org-operator">=</span><span class="org-string">'y'</span>)

<span class="org-comment-delimiter"># </span><span class="org-comment">Add combined legend</span>
<span class="org-variable-name">lines1</span>, <span class="org-variable-name">labels1</span> <span class="org-operator">=</span> ax1.get_legend_handles_labels()
<span class="org-variable-name">lines2</span>, <span class="org-variable-name">labels2</span> <span class="org-operator">=</span> ax2.get_legend_handles_labels()
ax1.legend(lines1 <span class="org-operator">+</span> lines2, labels1 <span class="org-operator">+</span> labels2, loc<span class="org-operator">=</span><span class="org-string">'upper left'</span>)

<span class="org-comment-delimiter"># </span><span class="org-comment">Layout and save</span>
plt.tight_layout()
plt.savefig(<span class="org-string">'posts_comments_analysis.svg'</span>)
<span class="org-keyword">return</span> <span class="org-string">'posts_comments_analysis.svg'</span>
</pre>
</div>

</details>


<figure id="org8363737">
<img src="https://sachachua.com/blog/2025/03/moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site/posts_comments_analysis.svg" alt="posts_comments_analysis.svg" class="org-svg" data-link="t">

</figure>

<p>
Timeline notes:
</p>

<ul class="org-ul">
<li>In this graph, comments are reported by the
timestamp of the comment, not the date of the
post.</li>
<li>In 2007 or so, I moved to Wordpress from
planner-rss.el. I think I eventually imported
those Wordpress comments into Disqus when I got
annoyed with Wordpress comments (Akismet?
notifications?).</li>
<li>In 2008 and 2009, I was working on enterprise
social computing at IBM. I made a few
presentations that were popular. Also, mentors
and colleagues posted lots of comments.</li>
<li>In 2012, I started my <a href="https://sachachua.com/blog/category/experiment/">5-year experiment with semi-retirement</a>.</li>
<li>In 2016, A+ was born, so I wrote much fewer posts.</li>
<li>In 2019/2020, I wrote a lot of blog posts
documenting how I was <a href="https://sachachua.com/blog/category/emacs/">running EmacsConf with
Emacs</a>, and other Emacs tweaks along the way. The
code is probably very idiosyncratic (&#x2026; unless
you happen to know other conference organizers
who like to do as much as possible within Emacs?
Even then, there are lots of assumptions in the
code), but maybe people picked up useful ideas
anyway. =)</li>
</ul>

<p>
What were my top 20 most-commented posts?
</p>

<details><summary>Emacs Lisp code for most-commented posts</summary>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">let*</span> ((json-object-type <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">alist</span>)
       (json-array-type <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">list</span>)
       (comments-json (json-read-file <span class="org-string">"~/proj/static-blog/_data/commentsCounts.json"</span>))
       (posts-json (json-read-file <span class="org-string">"~/proj/static-blog/_site/blog/all/index.json"</span>))
       (post-map (make-hash-table <span class="org-builtin">:test</span> <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">equal</span>)))
  <span class="org-comment-delimiter">;; </span><span class="org-comment">map permalink to title</span>
  (<span class="org-keyword">dolist</span> (post posts-json)
    (<span class="org-keyword">let</span> ((permalink (cdr (assoc <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">permalink</span> post)))
          (title (cdr (assoc <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">title</span> post))))
      (puthash permalink title post-map)))
  <span class="org-comment-delimiter">;; </span><span class="org-comment">Sort comments by count (descending)</span>
  (mapcar
   (<span class="org-keyword">lambda</span> (row)
     (list
      (cdr row)
            (org-link-make-string
       (concat <span class="org-string">"https://sachachua.com"</span> (symbol-name (car row)))
       (<span class="org-keyword">with-temp-buffer</span>
         (insert (<span class="org-keyword">or</span> (gethash (symbol-name (car row)) post-map) (symbol-name (car row))))
         (mm-url-decode-entities)
         (buffer-string)))))
   (seq-take
    (sort comments-json
          (<span class="org-keyword">lambda</span> (a b) (&gt; (cdr a) (cdr b))))
    n)))
</pre>
</div>

</details>

<table>


<colgroup>
<col class="org-right">

<col class="org-left">
</colgroup>
<tbody>
<tr>
<td class="org-right">97</td>
<td class="org-left"><a href="https://sachachua.com/blog/contact/"><i>blog/contact</i></a></td>
</tr>

<tr>
<td class="org-right">88</td>
<td class="org-left"><a href="https://sachachua.com/blog/2010/05/even-more-awesome-lotusscript-mail-merge-for-lotus-notes-microsoft-excel/">Even more awesome LotusScript mail merge for Lotus Notes + Microsoft Excel</a></td>
</tr>

<tr>
<td class="org-right">75</td>
<td class="org-left"><a href="https://sachachua.com/blog/about/"><i>blog/about</i></a></td>
</tr>

<tr>
<td class="org-right">45</td>
<td class="org-left"><a href="https://sachachua.com/blog/2013/05/how-to-learn-emacs-a-hand-drawn-one-pager-for-beginners/">How to Learn Emacs: A Hand-drawn One-pager for Beginners / A visual tutorial</a></td>
</tr>

<tr>
<td class="org-right">42</td>
<td class="org-left"><a href="https://sachachua.com/blog/2011/11/planning-an-emacs-based-personal-wiki-org-muse-hmm/">Planning an Emacs-based personal wiki – Org? Muse? Hmm…</a></td>
</tr>

<tr>
<td class="org-right">38</td>
<td class="org-left"><a href="https://sachachua.com/blog/2010/10/married/">Married!</a></td>
</tr>

<tr>
<td class="org-right">37</td>
<td class="org-left"><a href="https://sachachua.com/blog/2010/02/moving-from-testing-to-development/">Moving from testing to development</a></td>
</tr>

<tr>
<td class="org-right">36</td>
<td class="org-left"><a href="https://sachachua.com/blog/2009/12/what-can-i-help-you-learn-looking-for-mentees/">What can I help you learn? Looking for mentees</a></td>
</tr>

<tr>
<td class="org-right">33</td>
<td class="org-left"><a href="https://sachachua.com/blog/2009/07/lotus-notes-mail-merge-from-a-microsoft-excel-spreadsheet/">Lotus Notes mail merge from a Microsoft Excel spreadsheet</a></td>
</tr>

<tr>
<td class="org-right">30</td>
<td class="org-left"><a href="https://sachachua.com/blog/2009/04/nothing-quite-like-org-for-emacs/">Nothing quite like Org for Emacs</a></td>
</tr>

<tr>
<td class="org-right">30</td>
<td class="org-left"><a href="https://sachachua.com/blog/2012/05/org-mode-and-habits/">Org-mode and habits</a></td>
</tr>

<tr>
<td class="org-right">29</td>
<td class="org-left"><a href="https://sachachua.com/blog/2012/08/zomg-evernote-emacs/">zomg, Evernote and Emacs</a></td>
</tr>

<tr>
<td class="org-right">25</td>
<td class="org-left"><a href="https://sachachua.com/blog/2012/06/literate-programming-emacs-configuration-file/">Literate programming and my Emacs configuration file</a></td>
</tr>

<tr>
<td class="org-right">25</td>
<td class="org-left"><a href="https://sachachua.com/blog/2014/04/reinvesting-time-and-money-into-emacs/">Reinvesting time and money into Emacs</a></td>
</tr>

<tr>
<td class="org-right">23</td>
<td class="org-left"><a href="https://sachachua.com/blog/2008/05/the-gen-y-guide-to-web-20-at-work/">The Gen Y Guide to Web 2.0 at Work</a></td>
</tr>

<tr>
<td class="org-right">22</td>
<td class="org-left"><a href="https://sachachua.com/blog/2011/08/drupal-overriding-drupal-autocompletion-to-pass-more-parameters/">Drupal: Overriding Drupal autocompletion to pass more parameters</a></td>
</tr>

<tr>
<td class="org-right">21</td>
<td class="org-left"><a href="https://sachachua.com/blog/2011/07/rhetoric-and-the-manila-zoo-reflections-on-conversations-and-a-request-for-insight/">Rhetoric and the Manila Zoo; reflections on conversations and a request for insight</a></td>
</tr>

<tr>
<td class="org-right">20</td>
<td class="org-left"><a href="https://sachachua.com/blog/2010/07/this-is-a-test-post-from-org2blog/">This is a test post from org2blog</a></td>
</tr>

<tr>
<td class="org-right">19</td>
<td class="org-left"><a href="https://sachachua.com/blog/2010/01/agendas/">Agendas</a></td>
</tr>

<tr>
<td class="org-right">19</td>
<td class="org-left"><a href="https://sachachua.com/blog/2012/09/paper-tablet-and-tablet-pc-comparing-tools-for-sketchnoting/">Paper, Tablet, and Tablet PC: Comparing tools for sketchnoting</a></td>
</tr>
</tbody>
</table>

<p>
Top 3 by year. Note that this goes by the
timestamp of the post, not the comment, so even
old posts are in here.
</p>

<details><summary>Emacs Lisp code for most-commented posts by year</summary>
<div class="org-src-container">
<pre class="src src-emacs-lisp" id="org9bd8774">(<span class="org-keyword">let*</span> ((json-object-type <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">alist</span>)
       (json-array-type <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">list</span>)
       (comments-json (json-read-file <span class="org-string">"~/proj/static-blog/_data/commentsCounts.json"</span>))
       (posts-json (json-read-file <span class="org-string">"~/proj/static-blog/_site/blog/all/index.json"</span>))
       by-year)
  (<span class="org-keyword">setq</span> posts-json
        (mapcar
         (<span class="org-keyword">lambda</span> (post)
           (<span class="org-keyword">let</span> ((comments (alist-get (intern (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">permalink</span> post)) comments-json)))
             (<span class="org-keyword">if</span> comments
                 (cons (cons <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">comments</span> (alist-get (intern (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">permalink</span> post)) comments-json 0))
                       post)
               post)))
         posts-json))
  (<span class="org-keyword">setq</span> by-year
        (seq-group-by
         (<span class="org-keyword">lambda</span> (o)
           (format-time-string <span class="org-string">"%Y"</span>
                               (date-to-time
                                (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">date</span> o))
                               <span class="org-string">"America/Toronto"</span>))
         (seq-filter (<span class="org-keyword">lambda</span> (o) (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">comments</span> o)) posts-json)))
  (org-list-to-org
   (cons <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">unordered</span>
         (seq-keep
          (<span class="org-keyword">lambda</span> (year)
            (list
             (org-link-make-string (concat <span class="org-string">"https://sachachua.com/blog/"</span> (car year))
                                   (car year))
             (cons <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">unordered</span>
                   (mapcar
                    (<span class="org-keyword">lambda</span> (entry)
                      (list (format <span class="org-string">"%s (%d)"</span>
                                    (org-link-make-string
                                     (concat <span class="org-string">"https://sachachua.com"</span> (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">permalink</span> entry))
                                     (<span class="org-keyword">with-temp-buffer</span>
                                       (insert (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">title</span> entry))
                                       (mm-url-decode-entities)
                                       (buffer-string)))
                                    (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">comments</span> entry))))
                    (seq-take
                     (sort
                      (cdr year)
                      (<span class="org-keyword">lambda</span> (a b) (&gt; (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">comments</span> a)
                                       (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">comments</span> b))))
                     n)))))
          (nreverse by-year)))))
</pre>
</div>

</details>

<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2025">2025</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2025/01/using-image-dired-to-browse-the-latest-screenshots-from-multiple-directories/">Using image-dired to browse the latest screenshots from multiple directories</a> (2)</li>
<li><a href="https://sachachua.com/blog/2025/01/changing-planet-emacslife-com/">Changing planet.emacslife.com</a> (2)</li>
<li><a href="https://sachachua.com/blog/2025/03/2025-03-03-emacs-news/">2025-03-03 Emacs news</a> (2)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2024">2024</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2024/01/using-an-emacs-lisp-macro-to-define-quick-custom-org-mode-links-to-project-files/">Using an Emacs Lisp macro to define quick custom Org Mode links to project files; plus URLs and search</a> (6)</li>
<li><a href="https://sachachua.com/blog/2024/11/excerpts-from-a-conversation-with-john-wiegley-johnw-and-adam-porter-alphapapa-about-personal-information-management/">Excerpts from a conversation with John Wiegley (johnw) and Adam Porter (alphapapa) about personal information management</a> (5)</li>
<li><a href="https://sachachua.com/blog/2024/01/yay-emacs-2024-01-12-emacsconf-2023-report-svg-animation-embark-org-mode-links/">Yay Emacs 1: EmacsConf 2023 report, SVG animation, Embark, Org Mode links</a> (4)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2023">2023</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2023/09/how-i-keep-track-of-new-emacs-packages/">How I keep track of new Emacs packages</a> (3)</li>
<li><a href="https://sachachua.com/blog/2023/12/automatically-refiling-org-mode-headings-based-on-tags/">Automatically refiling Org Mode headings based on tags</a> (3)</li>
<li><a href="https://sachachua.com/blog/2023/01/building-up-my-tech-notes/">Building up my tech notes</a> (2)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2022">2022</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2022/08/recoloring-my-sketches-with-python/">Recoloring my sketches with Python</a> (5)</li>
<li><a href="https://sachachua.com/blog/2022/11/late-night-braindumps-by-talking-to-myself/">Late-night braindumps by talking to myself</a> (3)</li>
<li><a href="https://sachachua.com/blog/2022/01/2022-01-24-emacs-news/">2022-01-24 Emacs news</a> (2)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2021">2021</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2021/01/a-list-of-sharks-that-are-obligate-ram-ventilators/">A list of sharks that are obligate ram ventilators</a> (6)</li>
<li><a href="https://sachachua.com/blog/2021/04/org-mode-insert-youtube-video-with-separate-captions/">Org Mode: Insert YouTube video with separate captions</a> (6)</li>
<li><a href="https://sachachua.com/blog/2021/12/thinking-about-emacs-community-maintenance/">Thinking about Emacs community maintenance</a> (6)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2020">2020</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2020/07/why-i-love-free-software/">Why I love free software</a> (9)</li>
<li><a href="https://sachachua.com/blog/2020/06/pythonfontforgeorg-i-made-a-font-based-on-my-handwriting/">Python+FontForge+Org: I made a font based on my handwriting!</a> (7)</li>
<li><a href="https://sachachua.com/blog/2020/12/2020-12-14-emacs-news/">2020-12-14 Emacs news</a> (5)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2019">2019</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2019/06/turning-an-org-mode-outline-into-an-html-table-with-a-column-for-more-notes/">Turning an Org Mode outline into an HTML table with a column for more notes</a> (10)</li>
<li><a href="https://sachachua.com/blog/2019/07/tweaking-emacs-on-android-via-termux-xclip-xdg-open-syncthing-conflicts/">Tweaking Emacs on Android via Termux: xclip, xdg-open, syncthing conflicts</a> (9)</li>
<li><a href="https://sachachua.com/blog/2019/03/visual-book-notes-no-drama-discipline-2014/">Visual Book Notes: No-Drama Discipline (2014)</a> (6)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2018">2018</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2018/04/2018-04-09-emacs-news/">2018-04-09 Emacs news</a> (6)</li>
<li><a href="https://sachachua.com/blog/2018/01/a-and-household-life/">A- and household life</a> (5)</li>
<li><a href="https://sachachua.com/blog/2018/03/using-org-mode-latex-beamer-and-medibang-paint-to-make-a-childrens-book/">Using Org Mode, LaTeX, Beamer, and Medibang Paint to make a children's book</a> (4)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2017">2017</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2017/06/quick-notes-on-my-current-interface-for-time-tracking/">Quick notes on my current interface for time-tracking</a> (9)</li>
<li><a href="https://sachachua.com/blog/2017/12/working-around-my-phone-plans-lack-of-roaming/">Working around my phone plan’s lack of roaming</a> (8)</li>
<li><a href="https://sachachua.com/blog/2017/04/emacs-pasting-with-the-mouse-without-moving-the-point-mouse-yank-at-point/">Emacs: Pasting with the mouse without moving the point – mouse-yank-at-point</a> (5)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2016">2016</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2016/12/using-categories-organize-org-agenda/">Using categories to organize your Org agenda</a> (16)</li>
<li><a href="https://sachachua.com/blog/2016/01/2016-01-16-emacs-hangout/">2016-01-16 Emacs Hangout</a> (9)</li>
<li><a href="https://sachachua.com/blog/2016/03/microphthalmia-small-eye/">Microphthalmia: small eye</a> (8)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2015">2015</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2015/02/lets-virtual-emacs-conference-august-help-make-happen/">Let’s have a virtual Emacs conference in August – help me make it happen!</a> (18)</li>
<li><a href="https://sachachua.com/blog/2015/01/thinking-make-better-use-yasnippet-emacs-workflow/">Thinking about how to make better use of Yasnippet in my Emacs workflow</a> (17)</li>
<li><a href="https://sachachua.com/blog/2015/07/july-2015-emacs-hangout/">July 2015 Emacs Hangout</a> (13)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2014">2014</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2014/04/reinvesting-time-and-money-into-emacs/">Reinvesting time and money into Emacs</a> (25)</li>
<li><a href="https://sachachua.com/blog/2014/12/can-improve-organize-notes-org-mode/">Improving how I organize notes with Org Mode</a> (19)</li>
<li><a href="https://sachachua.com/blog/2014/12/emacs-m-y-helm-show-kill-ring/">Emacs: M-y as helm-show-kill-ring</a> (18)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2013">2013</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2013/05/how-to-learn-emacs-a-hand-drawn-one-pager-for-beginners/">How to Learn Emacs: A Hand-drawn One-pager for Beginners / A visual tutorial</a> (45)</li>
<li><a href="https://sachachua.com/blog/2013/04/brainstorming-ways-to-help-build-the-emacs-community/">Brainstorming ways to help build the Emacs community</a> (19)</li>
<li><a href="https://sachachua.com/blog/2013/08/emacs-how-i-organize-my-org-files/">Emacs: How I organize my Org files</a> (19)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2012">2012</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2012/05/org-mode-and-habits/">Org-mode and habits</a> (30)</li>
<li><a href="https://sachachua.com/blog/2012/08/zomg-evernote-emacs/">zomg, Evernote and Emacs</a> (29)</li>
<li><a href="https://sachachua.com/blog/2012/06/literate-programming-emacs-configuration-file/">Literate programming and my Emacs configuration file</a> (25)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2011">2011</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2011/11/planning-an-emacs-based-personal-wiki-org-muse-hmm/">Planning an Emacs-based personal wiki – Org? Muse? Hmm…</a> (42)</li>
<li><a href="https://sachachua.com/blog/2011/08/drupal-overriding-drupal-autocompletion-to-pass-more-parameters/">Drupal: Overriding Drupal autocompletion to pass more parameters</a> (22)</li>
<li><a href="https://sachachua.com/blog/2011/07/rhetoric-and-the-manila-zoo-reflections-on-conversations-and-a-request-for-insight/">Rhetoric and the Manila Zoo; reflections on conversations and a request for insight</a> (21)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2010">2010</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2010/05/even-more-awesome-lotusscript-mail-merge-for-lotus-notes-microsoft-excel/">Even more awesome LotusScript mail merge for Lotus Notes + Microsoft Excel</a> (88)</li>
<li><a href="https://sachachua.com/blog/2010/10/married/">Married!</a> (38)</li>
<li><a href="https://sachachua.com/blog/2010/02/moving-from-testing-to-development/">Moving from testing to development</a> (37)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2009">2009</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2009/12/what-can-i-help-you-learn-looking-for-mentees/">What can I help you learn? Looking for mentees</a> (36)</li>
<li><a href="https://sachachua.com/blog/2009/07/lotus-notes-mail-merge-from-a-microsoft-excel-spreadsheet/">Lotus Notes mail merge from a Microsoft Excel spreadsheet</a> (33)</li>
<li><a href="https://sachachua.com/blog/2009/04/nothing-quite-like-org-for-emacs/">Nothing quite like Org for Emacs</a> (30)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2008">2008</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2008/05/the-gen-y-guide-to-web-20-at-work/">The Gen Y Guide to Web 2.0 at Work</a> (23)</li>
<li><a href="https://sachachua.com/blog/2008/01/outlining-your-notes-with-org/">Outlining Your Notes with Org</a> (18)</li>
<li><a href="https://sachachua.com/blog/2008/01/tagging-in-org-plus-bonus-code-for-timeclocks-and-tags/">Tagging in Org – plus bonus code for timeclocks and tags!</a> (14)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2007">2007</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2007/12/clocking-time-with-emacs-org/">Clocking Time with Emacs Org</a> (18)</li>
<li><a href="https://sachachua.com/blog/2007/12/emacs-choosing-between-org-and-planner/">Emacs: Choosing between Org and Planner</a> (13)</li>
<li><a href="https://sachachua.com/blog/2007/12/wicked-cool-emacs-get-in-on-the-action/">Wicked Cool Emacs: get in on the action!</a> (10)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2006">2006</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2006/04/how-to-wear-a-malong/">How to wear a malong</a> (6)</li>
<li><a href="https://sachachua.com/blog/2006/09/what-makes-a-good-life/">What makes a good life?</a> (6)</li>
<li><a href="https://sachachua.com/blog/2006/09/emacs-linkedin-another-totally-idiosyncratic-bit-of-code/">Emacs + LinkedIn: Another totally idiosyncratic bit of code</a> (3)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2005">2005</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2005/11/emacs-its-all-about-people/">Emacs: It’s all about people</a> (4)</li>
<li><a href="https://sachachua.com/blog/2005/12/learning-bisaya/">Learning Bisaya</a> (4)</li>
<li><a href="https://sachachua.com/blog/2005/03/networking/">Networking</a> (3)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2004">2004</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2004/02/nethack-el/">nethack-el</a> (4)</li>
<li><a href="https://sachachua.com/blog/2004/03/rmail-labels/">RMAIL labels</a> (4)</li>
<li><a href="https://sachachua.com/blog/2004/11/sketch-website-design/">Sketch website design</a> (3)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2003">2003</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2003/11/cookordie-day-2-veal-sausage-and-potatoes/">CookOrDie Day 2: Veal sausage and potatoes</a> (4)</li>
<li><a href="https://sachachua.com/blog/2003/06/look-into-literate-programming/">Look into literate programming</a> (3)</li>
<li><a href="https://sachachua.com/blog/2003/08/automatically-detecting-proxy-settings/">Automatically detecting proxy settings</a> (3)</li>
</ul></li>
<li><a href="https://sachachua.com/blog/2002">2002</a>
<ul class="org-ul">
<li><a href="https://sachachua.com/blog/2002/06/hello-world-school-teaching-games/">Hello world, school, teaching, games ()</a> (1)</li>
</ul></li>
</ul>

<p>
As you can probably tell, I love writing about
Emacs, especially when people drop by in the
comments to:
</p>

<ul class="org-ul">
<li>share that they'd just learned about some small
thing I mentioned in passing and that it was
really useful for this other part of their
workflow that I totally wouldn't have guessed</li>
<li>point out a simpler package or built-in Emacs
function that also does whatever clever hack I
wrote about, just in a more polished way</li>
<li>link to a blog post or code snippet where
they've borrowed the idea and added their own
spin</li>
</ul>

<p>
I want to keep having those sorts of
conversations.
</p>
</div>
</div>
<div id="outline-container-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-deleting-spam-comments-via-the-disqus-web-interface-and-spookfox" class="outline-2">
<h3 id="moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-deleting-spam-comments-via-the-disqus-web-interface-and-spookfox">Deleting spam comments via the Disqus web interface and Spookfox</h3>
<div class="outline-text-2" id="text-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-deleting-spam-comments-via-the-disqus-web-interface-and-spookfox">
<p>
8000+ comments are a lot to read, but it should be
pretty straightforward to review the comments at
least until 2016 or so, and then just clean out
spam as I come across it after that. I used the
Disqus web interface to delete spam comments since
the <code>isSpam</code> attribute didn't seem to be reliable.
The web interface pages through comments 25 items
at a time and doesn't seem to let you select all
of them, so I started tinkering around with using
<a href="https://github.com/bitspook/spookfox">Spookfox</a> to automate this. Spookfox lets me
control Mozilla Firefox from Emacs Lisp.
</p>


<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">progn</span>
  <span class="org-comment-delimiter">;; </span><span class="org-comment">select all</span>
  (spookfox-eval-js-in-active-tab <span class="org-string">"document.querySelector('.mod-bar__check input').click()"</span>)
  (wait-for 1)
  <span class="org-comment-delimiter">;; </span><span class="org-comment">delete</span>
  (spookfox-eval-js-in-active-tab <span class="org-string">"document.querySelectorAll('</span><span class="org-string"><span class="org-constant">.mod-bar__button</span></span><span class="org-string">')[2].click()"</span>)
  (wait-for 2)
  <span class="org-comment-delimiter">;; </span><span class="org-comment">click OK, which should make the list refresh</span>
  (spookfox-eval-js-in-active-tab <span class="org-string">"btn = document.querySelectorAll('</span><span class="org-string"><span class="org-constant">.mod-bar__button</span></span><span class="org-string">')[1]; if (btn.textContent.match('</span><span class="org-string"><span class="org-constant">OK</span></span><span class="org-string">')) btn.click();"</span>)
  (wait-for 4)
  <span class="org-comment-delimiter">;; </span><span class="org-comment">backup: (spookfox-eval-js-in-active-tab "window.location.href = '</span><span class="org-comment"><span class="org-constant">https://sachac.disqus.com/admin/moderate/spam</span></span><span class="org-comment">'")</span>
  )
</pre>
</div>


<p>
I got to the end of the spam comments after maybe
10 or 20 pages, though, so maybe Disqus had
auto-deleted most of the spam comments.
</p>

<p>
It's almost amusing, paging through all these
spammy attempts at link-building and product
promotion. I didn't want to click on any of the
links since there might be malware, so sometimes I
used <code>curl</code> to check the site. Most of the old
spam links I checked don't even have working
domains any more. Anything that needed spam didn't
really have lasting power. It was all very "My
name is Ozymandias, king of kings: / Look on my
works, ye Mighty, and despair!"&#x2026; and then gone.
</p>
</div>
</div>
<div id="outline-container-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-modifying-eleventy-import-disqus-for-my-site" class="outline-2">
<h3 id="moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-modifying-eleventy-import-disqus-for-my-site">Modifying eleventy-import-disqus for my site</h3>
<div class="outline-text-2" id="text-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-modifying-eleventy-import-disqus-for-my-site">
<p>
Back to eleventy-import-disqus. I followed the
directions to make a contentMap.json and removed
the trailing <code>,</code> from the last entry so that the
JSON could be parsed.
</p>

<p>
<a href="https://github.com/sachac/eleventy-import-disqus-sachachua.com/tree/sachachua.com">Modifications to eleventy-import-disqus:</a>
</p>
<ul class="org-ul">
<li>The original code created all the files in the same directory, so I changed it to create the same kind of nested structure I use (generally <code>./blog/yyyy/mm/post-slug/index.html</code> and <code>./blog/yyyy/mm/post-slug/index.11tydata.json</code>). I decided to store the Disqus comments in <code>index.json</code>, which is lower-priority than <code>.11tydata.json.</code> <a href="https://stackoverflow.com/questions/13542667/create-directory-when-writing-to-file-in-node-js">fs-extra</a> made this easier by creating all the parent directories.</li>
<li>Ignored deleted messages</li>
<li>Discarded avatars</li>
<li>Did some reporting to help me review potential spam</li>
<li>Reparented messages if I deleted their parent posts</li>
<li>Indent the thread JSON nicely in case I want to add or remove comments by hand</li>
</ul>

<p>
With the thread JSON files, my blog takes 143
seconds to generate, versus 133 seconds without
the comments. +10 seconds isn't too bad. I was
worried that it would be longer, since I added
2,088 data JSON files to the build process, but I
guess 11ty is pretty efficient.
</p>
</div>
</div>
<div id="outline-container-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-next-steps" class="outline-2">
<h3 id="moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-next-steps">Next steps</h3>
<div class="outline-text-2" id="text-moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site-next-steps">
<p>
It had been nice to have a comment form that
people could fill in from anywhere and which
shared their comments without needing my (often
delayed) intervention. I learned lots of things
from what people shared. Sometimes people even had
discussions with each other, which was extra cool.
Still, I think it might be a good time to
experiment with alternatives. <a href="mailto:sacha@sachachua.com">Plain e-mail</a> for
now, I guess, maybe with a nudge asking people if
I could share their comments. <a href="https://sachachua.com/blog/2025/03/tweaking-my-11ty-blog-to-link-to-the-mastodon-post-defined-in-an-org-mode-property/">Mastodon</a>, too -
could be fun to make it easy to add a toot to the
static comments from <a href="https://codeberg.org/martianh/mastodon.el">mastodon.el</a> or from my Org
Mode inbox. (<mark>Update 2025-03-30:</mark> <a href="https://sachachua.com/dotemacs#mastodon-adding-mastodon-toots-as-comments-in-my-11ty-static-blog">Adding Mastodon
toots as comments in my 11ty static blog</a>) Might be
good to figure out <a href="https://webmention.io/">Webmentions</a>, too. (But then
<a href="https://brainbaking.com/post/2023/05/why-i-retired-my-webmention-server/">other people have been dealing with spam
Webmentions, of course</a>.)
</p>

<p>
Comment counts can be useful social signals for
interesting posts. I haven't added comment counts
to the lists of blog posts yet.
eleventy-import-disqus created a
commentsCounts.json, which I could use in my
templates. However, I might change the comments in
the per-post .json file if I figure out how to
include Mastodon comments, so I may need to update
that file or recalculate it from the posts.
</p>

<p>
Many of the blogs I read have shifted away from
commenting systems, and the ones who still have
comments on seem to be bracing for <a href="https://www.zylstra.org/blog/2025/03/incoming-ai-generated-comment-spam/">AI-generated
comment spam</a>. I'm not sure I like the way the
Internet is moving, but maybe in this little
corner, we can still have conversations across
time. Comments are such a wonderful part of
learning out loud. I wonder how we can keep
learning together.</p>
</div>
</div>
<div><a href="https://sachachua.com/blog/2025/03/moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site/index.org">View org source for this post</a></div>
<p>You can <a href="https://social.sachachua.com/@sacha/statuses/01JQM0XSA0W90C9Y4WKA808MTY" target="_blank" rel="noopener noreferrer">comment on Mastodon</a>, <a href="https://sachachua.com/blog/2025/03/moving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site/#comment">view 8 comments</a>, or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2025%2F03%2Fmoving-18-years-of-comments-out-of-disqus-and-into-my-11ty-static-site%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Old-school blogger</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2025/03/old-school-blogger/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2025-03-20T15:05:32Z</updated>
    <published>2025-03-20T15:05:32Z</published>
    <category term="blogging" />
<category term="writing" />
		<id>https://sachachua.com/blog/2025/03/old-school-blogger/</id>
		<content type="html"><![CDATA[<p>
</p><div class="sketch-full"><a class="photoswipe" href="https://sketches.sachachua.com/filename/2025-03-16-01%20Old-school%20blogger%20&#45;&#45;%20blogging%20writing.jpeg" data-src="https://sketches.sachachua.com/static/2025-03-16-01%20Old-school%20blogger%20&#45;&#45;%20blogging%20writing.jpeg" data-title="2025-03-16-01 Old-school blogger &#45;&#45; blogging writing" data-w="2764" data-h="2060"><picture>
      <img src="https://sketches.sachachua.com/static/2025-03-16-01%20Old-school%20blogger%20&#45;&#45;%20blogging%20writing.jpeg" width="2764" height="2060" alt="2025-03-16-01 Old-school blogger &#45;&#45; blogging writing" loading="lazy" style="max-height: 90vw; height: auto; width: auto" decoding="async">
      <figcaption>2025-03-16-01 Old-school blogger &#45;&#45; blogging writing</figcaption>
    </picture></a></div>
<p></p>

<details class="code-details" style="padding: 1em;
                 border-radius: 15px;
                 font-size: 0.9em;
                 box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;">
                  <summary><strong>Text from sketch</strong></summary>
<p>
Old-school blogger
</p>

<p>
[timeline showing different strands braided together]
</p>

<p>
I started blogging in 2001 (really, more like 2002), as a university student who had started playing around enjoyed learning out loud. Both blogging and Emacs continued through:
</p>

<ul class="org-ul">
<li>teaching computer science</li>
<li>going on a technical internship in Japan</li>
<li>taking up graduate studies</li>
<li>working at IBM</li>
<li>experimenting with consulting and semi-retirement</li>
<li>parenting</li>
</ul>

<p>
directly related to blogging: grad studies, working, experimenting
</p>

<p>
It's wonderful having such a long archive. I can trace my growth. I've changed a lot over the past 24 years. I miss being so optimistic and energetic, but who I am now and who I'm becoming are also okay.
</p>

<p>
[drawing of the butterfly life cycle]
</p>

<ul class="org-ul">
<li>caterpillar</li>
<li>chrysalis: We're in this messy stage where I digest myself and move my insides around</li>
<li>butterfly: maybe someday</li>
</ul>

<p>
Learning out loud by blogging:
</p>
<ul class="org-ul">
<li>Springboard: Writing as I learn means I can use my notes to pick up from where I left off.</li>
<li>Sometimes my notes help other people.</li>
<li>Sometimes people share what they've been learning.</li>
<li>Writing helps me gather my tribe.</li>
</ul>

<p>
Questions to explore:
</p>
<ul class="org-ul">
<li>What do I want to learn? How?</li>
<li>What's nearby?</li>
<li>What might be useful
<ul class="org-ul">
<li>to my future self</li>
<li>to others</li>
</ul></li>
</ul>

<p>
Looking forward - I want to&#x2026;
</p>
<ul class="org-ul">
<li>draw more. It's fun.</li>
<li>deepen my reflections.</li>
<li>learn more.</li>
<li>prepare so I can keep doing this.</li>
</ul>

<p>
How can I improve workflows for capturing/thinking/sharing/finding?
</p>

<p>
What can I do so I can keep learning and writing all my life? How can I get even better at it?
</p>

<p>
sach.ac/2025-03-16-01
</p>


</details>

<p>
<a href="http://scripting.com/2025/03/15.html#a135901">Dave Winer's looking for old school bloggers</a> (<a href="http://scripting.com/2025/03/17.html#a130705">also
this</a>) so that nudged me to think about how and why
I blog.
</p>

<div class="sticky-toc" id="org190bfc0">
<div id="text-table-of-contents" role="doc-toc">
<ul>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#old-school-blogger-still-writing">Still writing</a></li>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#old-school-blogger-writing-workflow">Writing workflow</a></li>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#old-school-blogger-reading-workflow">Reading workflow</a></li>
<li><a href="https://sachachua.com/blog/feed/atom/index.xml#old-school-blogger-keeping-an-eye-on-the-future">Keeping an eye on the future</a></li>
</ul>
</div>

</div>
<div id="outline-container-old-school-blogger-still-writing" class="outline-2">
<h3 id="old-school-blogger-still-writing">Still writing</h3>
<div class="outline-text-2" id="text-old-school-blogger-still-writing">
<p>
From <a href="https://sachachua.com/blog/2024/10/how-to-take-smart-notes-sonke-ahrens-2017/">How to Take Smart Notes</a> (Sönke Ahrens):
</p>

<blockquote>
<p>
If you want to learn something for the long run,
you have to write it down. If you want to really
understand something, you have to translate it
into your own words.
</p>
</blockquote>

<p>
Writing and sharing are part of how I learn.
Taking notes helps me learn things that are bigger
than my working memory or my uninterrupted time
segments. Sharing my notes helps me find them
again later on, since I can search the Internet
from my phone. Also, if I share my notes,
sometimes I get to learn from other people too,
and sometimes my notes help people figure out
stuff and then they can build on that.
</p>

<p>
It makes sense to me to share these notes on a
blog on my own domain, with a chronological view
and an RSS feed that makes it easier for other
people to check for updates if they want. Well,
some other people. I suppose RSS readers are still
a fairly technical sort of thing, and I don't
particularly like posting on platforms like
Facebook or LinkedIn. Anyway, I'll just keep
writing here, and maybe people will come across
posts via search engines or figure out how to get
updates however they want to.
</p>

<details><summary>Summarizing posts</summary>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">let*</span> ((annotations <span class="org-highlight-quoted-quote">'</span>((2001 <span class="org-string">"university"</span>)
                      (2003 <span class="org-string">"graduated, teaching"</span>)
                      (2004 <span class="org-string">"internship in Japan"</span>)
                      (2005 <span class="org-string">"grad school"</span>)
                      (2007 <span class="org-string">"working at IBM"</span>)
                      (2008 <span class="org-string">"drawing"</span>)
                      (2012 <span class="org-string">"experiment with semi-retirement"</span>)
                      (2016 <span class="org-string">"A+ was born"</span>)
                      (2019 <span class="org-string">"EmacsConf, COVID-19"</span>)
                      (2022 <span class="org-string">"SuperNote A5X"</span>)
                      (2023 <span class="org-string">"even more EmacsConf automation"</span>)
                      (2024 <span class="org-string">"cargo bike"</span>)
                      (2025 <span class="org-string">"added iPad to the mix"</span>)))
       (json-array-type <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">list</span>)
       (json-object-type <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">alist</span>)
       (posts-by-year
        (mapcar
         (<span class="org-keyword">lambda</span> (o) (cons (car o) (length (cdr o))))
         (seq-group-by
          (<span class="org-keyword">lambda</span> (o) (substring (alist-get <span class="org-highlight-quoted-quote">'</span><span class="org-highlight-quoted-symbol">date</span> o) 0 4))
          (json-read-file <span class="org-string">"~/proj/static-blog/_site/blog/all/index.json"</span>)))))
  (append
   <span class="org-highlight-quoted-quote">'</span>((<span class="org-string">"Year"</span> <span class="org-string">"Posts"</span> <span class="org-string">"Note"</span>) hline)
   (<span class="org-keyword">cl-loop</span>
    for i from 2001 to 2025
    collect
    (list (format <span class="org-string">"[[https://sachachua.com/blog/%d][%d]]"</span>
          i i)
          (alist-get (number-to-string i) posts-by-year nil nil <span class="org-highlight-quoted-quote">#'</span><span class="org-highlight-quoted-symbol">string=</span>)
          (<span class="org-keyword">or</span> (car (alist-get i annotations)) <span class="org-string">""</span>)))))
</pre>
</div>

</details>

<table>


<colgroup>
<col class="org-left">

<col class="org-right">

<col class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">Year</th>
<th scope="col" class="org-right">Posts</th>
<th scope="col" class="org-left">Note</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2001">2001</a></td>
<td class="org-right">3</td>
<td class="org-left">university</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2002">2002</a></td>
<td class="org-right">31</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2003">2003</a></td>
<td class="org-right">869</td>
<td class="org-left">graduated, teaching</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2004">2004</a></td>
<td class="org-right">971</td>
<td class="org-left">internship in Japan</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2005">2005</a></td>
<td class="org-right">678</td>
<td class="org-left">grad school</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2006">2006</a></td>
<td class="org-right">877</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2007">2007</a></td>
<td class="org-right">510</td>
<td class="org-left">working at IBM</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2008">2008</a></td>
<td class="org-right">421</td>
<td class="org-left">drawing</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2009">2009</a></td>
<td class="org-right">452</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2010">2010</a></td>
<td class="org-right">399</td>
<td class="org-left">Quantified Self</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2011">2011</a></td>
<td class="org-right">397</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2012">2012</a></td>
<td class="org-right">361</td>
<td class="org-left">experiment with semi-retirement</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2013">2013</a></td>
<td class="org-right">359</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2014">2014</a></td>
<td class="org-right">339</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2015">2015</a></td>
<td class="org-right">251</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2016">2016</a></td>
<td class="org-right">141</td>
<td class="org-left">A+ was born</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2017">2017</a></td>
<td class="org-right">145</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2018">2018</a></td>
<td class="org-right">176</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2019">2019</a></td>
<td class="org-right">121</td>
<td class="org-left">EmacsConf, COVID-19</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2020">2020</a></td>
<td class="org-right">94</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2021">2021</a></td>
<td class="org-right">132</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2022">2022</a></td>
<td class="org-right">78</td>
<td class="org-left">SuperNote A5X</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2023">2023</a></td>
<td class="org-right">122</td>
<td class="org-left">even more EmacsConf automation</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2024">2024</a></td>
<td class="org-right">148</td>
<td class="org-left">cargo bike</td>
</tr>

<tr>
<td class="org-left"><a href="https://sachachua.com/blog/2025">2025</a></td>
<td class="org-right">49</td>
<td class="org-left">added iPad to the mix</td>
</tr>
</tbody>
</table>

<p>
I don't see myself giving up these tools until I
really can't use them any more. I'm keeping an eye
out for assistive technology that might help me
work around my limitations and the likely
cognitive/physical decline I'll eventually run
into. I'm encouraged by the fact that quite a few
people manage to keep learning and writing even
into their <a href="http://nocache.azcentral.com/thingstodo/arts/articles/20121125authors-work-old-career-roth-wolfe-leonard.html">80s and 90s</a>.
</p>

<p>
Some weeks, <a href="https://sachachua.com/blog/category/emacs-news">Emacs News</a> is all I can squeeze in: a
long categorized list of links. When I have more
time, I add little bits of code, drawings,
reflections.
</p>

<p>
I love writing about little tweaks. Mostly that's
about Emacs. I love the way I can shape it into
something that fits <i>me</i>.
</p>

<p>
I like to <a href="https://sachachua.com/topic/visual-book-notes/">summarize books</a> and ideas as sketchnotes
so that I have a chance of remembering what I want
to learn from them. Also, the drawings are handy
for sharing with others, and they're a way of
giving back.
</p>

<p>
I'm slowly learning to write about life in a way
that helps me learn more while respecting people's
privacy. I like doing little experiments. Even
tinier than the ones described in <a href="https://nesslabs.com/book">Tiny
Experiments</a>. Not "I will write 100 blog posts over
the next 100 days," but rather, "What if I
postpone fretting about A+'s homework until
Saturday? What happens then?"
</p>
</div>
</div>
<div id="outline-container-old-school-blogger-writing-workflow" class="outline-2">
<h3 id="old-school-blogger-writing-workflow">Writing workflow</h3>
<div class="outline-text-2" id="text-old-school-blogger-writing-workflow">
<p>
After I get the kiddo through the morning routine
and ready for virtual school, I usually play piano
for about an hour or so. Then it's recess and some
more hugs, and then I settle down for some writing
or drawing. The weather is getting better, so I'm
looking forward to moving some of that outside.
Maybe I'll dust off those baby monitor apps so I
can hear if A+ needs any help.
</p>

<p>
I mostly write on my laptop using <a href="https://orgmode.org/">Org Mode</a> in
<a href="https://www.gnu.org/s/emacs/">Emacs</a>. Org Mode is great for <a href="https://www.offerzen.com/blog/literate-programming-empower-your-writing-with-emacs-org-mode">literate programming</a>.
I can mix my notes and my code however I like.
</p>

<p>
I don't write in a straightforward way. I jump
around. I go on tangents and down rabbit-holes. It
helps a little if I've sketched my thoughts
beforehand, like for this post, or if I've done
some <a href="https://sachachua.com/blog/2023/12/audio-braindump-workflow-tweaks-adding-org-mode-hyperlinks-to-recordings-based-on-keywords/">audio braindumping</a> to help me figure out
where the interesting thoughts are. Sometimes I
capture little thoughts on my phone and then move
them to the post I'm working on. I'm trying to
figure out how to <a href="https://sachachua.com/blog/2025/03/playing-with-chunk-size-when-writing/">chunk my thoughts better</a>.
</p>

<p>
I have a lot of Emacs tweaks to make it easier to
link to <a href="https://sachachua.com/dotemacs#linking-to-blog-posts">blog posts</a>, <a href="https://sachachua.com/dotemacs#org-bookmarks">bookmarks</a>, <a href="https://sachachua.com/dotemacs#org-mode-sketch-links">sketches</a>, <a href="https://sachachua.com/blog/2024/10/yay-emacs-inserting-links-with-consult-omni/">sites
from search results</a>. I like
<a href="https://sachachua.com/dotemacs#org-mode-writing-about-sketches-and-including-their-text">including the text of sketches</a>, too.
</p>

<p>
I use the <a href="https://www.11ty.dev/">11ty</a> static site generator to make my
blog. I switched to it a few years ago because I
didn't want to worry about keeping Wordpress
secure. I don't have room for many programming
languages in my brain at the moment, so I like the
fact that 11ty uses JavaScript. It takes me about
five minutes to compile my blog.
</p>
</div>
</div>
<div id="outline-container-old-school-blogger-reading-workflow" class="outline-2">
<h3 id="old-school-blogger-reading-workflow">Reading workflow</h3>
<div class="outline-text-2" id="text-old-school-blogger-reading-workflow">
<p>
From <a href="https://dancullum.com/2025/03/the-more-i-read/">Dan Cullum: The more I read</a>:
</p>

<blockquote>
<p>
There is a strong correlation between the amount I’m reading, and the ideas I have for this blog.
When I’m reading a lot, I feel like I have ideas coming out my eyes.
</p>
</blockquote>

<p>
Reading makes me want to write, too.
</p>

<p>
I love the <a href="https://www.torontopubliclibrary.ca/">Toronto Public Library</a> enough to
transplant myself from the tropics and learn how
to deal with winter. I've been reading more
e-books lately. It's easier to highlight e-books
compared to paper books. I can pick them up and
put them down easily, and keep the pages open when
I'm taking notes. I don't have to worry about
misplacing them, either. I have some code to <a href="https://sachachua.com/blog/2024/11/org-mode-format-libby-book-highlights-exported-as-json/">grab
my highlights as a JSON</a>, and then I can do things
with them: include them in blog posts, add them to
my personal notes, etc.
</p>

<p>
Not everything is available as an e-book, though,
and sometimes the e-books have long hold times.
Paper books are still handy enough.
</p>

<p>
I like reading blogs. They're much shorter than
books are, and much less fluffy. Sometimes I feel
like mainstream printed books have a lot of
padding because of the considerations of the
publishing industry: the book must be a certain
size so it doesn't get lost on the bookstore
shelf; the book must have a certain weight and
thickness so people feel that it's worth $25. Blog
posts can just get to the core of the idea instead
of belabouring the point. I like the fractal
<a href="https://kottke.org/24/11/the-powerful-density-of-hypertextual-writing">density of hyperlinked text</a>, too, and the
conversational possibilities of it. It's a lot
easier to bounce an idea back and forth to develop
it when you can post in a day instead of waiting
for a year for a book to be published.
</p>

<p>
I like reading on the new iPad. It's smaller than
my laptop and bigger than my phone. It's easy to
browse through blogs on it, unlike on my
Supernote. I'm starting to develop a workflow for
reading and writing smaller snippets: <a href="https://social.sachachua.com/@sacha/statuses/01JPH0VHDQ9V9KB5TD36QGGWVQ">(toot)</a>
</p>

<ol class="org-ol">
<li>Read in NetNewsWire.</li>
<li>Open interesting posts in Chrome on the iPad.</li>
<li>Highlight the text.</li>
<li>Use "Copy Link with Highlight".</li>
<li>Tap on the selection again. Use "Share" to send
it to <a href="https://apps.apple.com/us/app/ice-cubes-for-mastodon/id6444915884">Ice Cubes</a>, a Mastodon client that can
post to my GoToSocial instance and let me use
my full post limit (5,000 characters,
mwahahahaha).</li>
<li>Paste the link into the toot, add my own thoughts, and post it.</li>
</ol>

<p>
<a href="https://sachachua.com/blog/2025/02/adding-an-anchor-to-a-paragraph-in-org-mode-html-export/#working-with-smaller-chunks-of-thoughts-adding-anchors-to-paragraphs-in-org-mode-html-export-text-fragments">I like linking to text fragments.</a> Sharing from a
webpage on my Android phone does this
automatically. "Copy Highlight as Link" works from
Chrome on the iPad. It saves people that little
bit of scrolling or finding, although I suppose it
would be helpful for people to go through the
context before that selection. Alternatively, I
could share directly from NetNewsWire and just
link to the blog post instead of the text.
</p>

<p>
I like making <a href="https://sachachua.com/topic/visual-book-notes">visual book notes</a>. They help me <a href="https://sachachua.com/blog/2013/04/how-i-read-books-and-do-visual-book-reviews/">read
a book well</a>, and turning the sketch into a blog
post gives me more opportunities to revisit it:
when I write the post, and if someone comments or
shares it.
</p>

<p>
Eventually I want to dust off my code for
<a href="https://sachachua.com/dotemacs#mastodon-insert-statuses">collecting Mastodon posts into a blog post</a>, and
maybe also re-establish a weekly review process.
</p>

<p>
<mark>Tangent:</mark> Check out <a href="https://sachachua.com/blog/2025/03/reading-more-blogs-emacs-lisp-listing-blogs-based-on-an-opml-file/">Reading more blogs; Emacs
Lisp: Listing blogs based on an OPML file</a> for a
table of the blogs I'm reading, along with the
code I used to make a table of blogs, their latest
post (as of the time I wrote my post, of course),
and the post date.
</p>
</div>
</div>
<div id="outline-container-old-school-blogger-keeping-an-eye-on-the-future" class="outline-2">
<h3 id="old-school-blogger-keeping-an-eye-on-the-future">Keeping an eye on the future</h3>
<div class="outline-text-2" id="text-old-school-blogger-keeping-an-eye-on-the-future">
<p>
As the kiddo becomes more independent ("Mom, I'm
9, you don't have to fret about my jacket"), I'll
have more time for myself. This is a good time to
go bike and walk and explore outside, and to go
deep and wide into our interests as a family. I do
about 2-4 hours of consulting a week, just the
stuff I'm interested in. (<mark>TODO:</mark> There's a
tangent I want to write about <a href="https://medcircle.com/articles/adhd-interest-based-nervous-system/">interest-based
nervous systems</a>, which I notice in both A+ and
myself, and probably building on <a href="https://sachachua.com/blog/2014/03/reflecting-goals-time/">this 2014
reflection on having a buffet of goals</a>.) The rest
is life time, divided among the things we want to
learn/do/share and the things we do to take care
of ourselves.
</p>

<p>
Even though I have increasing autonomy when it
comes to time, and an increasing amount of focused
time, I still haven't gotten to the bottom of my
idea list or my to-write list. I don't think I'll
ever get to the bottom of those lists, actually. I
come up with ideas faster than I can do them.
That's a good problem to have.
</p>

<p>
It makes sense to prepare for a couple of changes
that will likely come up:
</p>

<ul class="org-ul">
<li><a href="https://en.wikipedia.org/wiki/Presbyopia">Age-related farsightedness</a>: It'll
probably get harder to read small text, and I
might eventually need to juggle my regular
glasses as well as reading glasses. (W- already
does this occasionally. He prefers having
different pairs of glasses instead of bifocals
or progressives, and his reasons seem sound. I
don't want to have to adopt different postures
to see out of different zones of glasses.)
Developing good workflows for reading will
probably help here. Also, the cargo vests I wear
will probably help me with the "Where are my
glasses?" problem.</li>

<li>Menopause will probably rewire my brain a lot. I
hear <a href="https://axiawh.com/resources/menopause-and-brain-fog/">brain fog and tip-of-the-tongue</a> can be
challenging (see also <a href="https://www.tandfonline.com/doi/full/10.1080/13697137.2022.2122792#d1e233">Brain fog in menopause</a>).</li>

<li>My mom is 79 and running into issues with
cognitive and physical decline. She has a hard
time typing, speaking, remembering, deciding, or
feeling good. On the other hand, there are
examples of people who have stayed sharp for
decades. There are lots of factors that are
beyond my control. Still, it would be nice to
see if I can stack the deck a little. So yes to:
<ul class="org-ul">
<li>walks, bike rides, exercise, and maybe I can
figure out a fun way to improve strength;</li>
<li>lots of learning and sharing and connecting</li>
<li>and experiments with technological and
cognitive aids, like speech recognition to
work around typing, <a href="https://github.com/tvraman/emacspeak">text-to-speech interfaces</a>
to work around vision, notes to work around
working memory, and maybe large language
models to work around issues with recall.</li>
<li>&#x2026; and I might as well learn Morse code or
explore accessibility tools, just in case I'm
limited to <a href="https://science.howstuffworks.com/dictionary/famous-scientists/physicists/stephen-hawking5.htm">twitching cheek muscles</a> or
something like that.</li>
</ul></li>
</ul>

<p>
The life expectancy at birth for the Philippines
for <a href="https://countryeconomy.com/demography/life-expectancy/philippines">women born in 1983</a> is ~65 years; <a href="https://countryeconomy.com/demography/life-expectancy/canada">in Canada</a>,
about ~80 years. I want to keep learning and
writing and sharing for as many of those years as
I can.
</p>

<p>
<a href="https://social.sachachua.com/@sacha/statuses/01JPT50YE4CHQNQ65TM8MP86JT">See discussion on Mastodon</a>
</p>
</div>
</div>
<div><a href="https://sachachua.com/blog/2025/03/old-school-blogger/index.org">View org source for this post</a></div>
<p>You can <a href="https://social.sachachua.com/@sacha/statuses/01JPT50YE4CHQNQ65TM8MP86JT" target="_blank" rel="noopener noreferrer">comment on Mastodon</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2025%2F03%2Fold-school-blogger%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry>
</feed>