<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on Thanos Apollo</title>
    <link>https://thanosapollo.org/posts/</link>
    <description>Recent content in Posts on Thanos Apollo</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Sat, 04 Apr 2026 00:00:00 +0300</lastBuildDate>
    <atom:link href="https://thanosapollo.org/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Bringing jabber.el Back From the Dead</title>
      <link>https://thanosapollo.org/posts/emacs-jabber-revival/</link>
      <pubDate>Sat, 04 Apr 2026 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-jabber-revival/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://xmpp.org/software/jabber-el/&#34;&gt;jabber.el&lt;/a&gt; is an XMPP client for Emacs, originally written in 2003.
Development slowed over the years, though contributors kept the package
working across Emacs releases.&lt;/p&gt;
&lt;p&gt;I took over as maintainer with the goal of modernizing the protocol
support.&lt;/p&gt;
&lt;p&gt;Now, jabber.el is &lt;strong&gt;the most XEP-complete text-based client&lt;/strong&gt; in
existence.&lt;/p&gt;
&lt;h2 id=&#34;what-changed&#34;&gt;What Changed&lt;/h2&gt;
&lt;p&gt;For those, like me, who count XEPs like Pokemon:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OMEMO encryption&lt;/strong&gt; (XEP-0384) via a C dynamic module wrapping &lt;a href=&#34;https://codeberg.org/picomemo/picomemo&#34;&gt;picomemo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OMEMO media sharing&lt;/strong&gt; (XEP-0454)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenPGP for XMPP&lt;/strong&gt; (XEP-0373) using Emacs&amp;rsquo; built-in EPG&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stream Management&lt;/strong&gt; (XEP-0198) with session resume&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Archive Management&lt;/strong&gt; (XEP-0313)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Carbons&lt;/strong&gt; (XEP-0280)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delivery Receipts&lt;/strong&gt; (XEP-0184) and &lt;strong&gt;Chat Markers&lt;/strong&gt; (XEP-0333)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Correction&lt;/strong&gt; (XEP-0308), &lt;strong&gt;Replies&lt;/strong&gt; (XEP-0461), &lt;strong&gt;Moderation&lt;/strong&gt; (XEP-0424/0425)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chat State Notifications&lt;/strong&gt; (XEP-0085)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client State Indication&lt;/strong&gt; (XEP-0352)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blocking Command&lt;/strong&gt; (XEP-0191)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP File Upload&lt;/strong&gt; (XEP-0363)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct TLS&lt;/strong&gt; (XEP-0368) with dual SRV lookup&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real Time Text&lt;/strong&gt; (XEP-0301)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PubSub&lt;/strong&gt; (XEP-0060)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bookmarks&lt;/strong&gt; (XEP-0402 with XEP-0048 fallback)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite message storage&lt;/strong&gt; replacing flat-file history&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MUC Self-Ping&lt;/strong&gt; (XEP-0410)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Almost caught them all&lt;/em&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://xmpp.org/software/jabber-el/">jabber.el</a> is an XMPP client for Emacs, originally written in 2003.
Development slowed over the years, though contributors kept the package
working across Emacs releases.</p>
<p>I took over as maintainer with the goal of modernizing the protocol
support.</p>
<p>Now, jabber.el is <strong>the most XEP-complete text-based client</strong> in
existence.</p>
<h2 id="what-changed">What Changed</h2>
<p>For those, like me, who count XEPs like Pokemon:</p>
<blockquote>
<ul>
<li><strong>OMEMO encryption</strong> (XEP-0384) via a C dynamic module wrapping <a href="https://codeberg.org/picomemo/picomemo">picomemo</a></li>
<li><strong>OMEMO media sharing</strong> (XEP-0454)</li>
<li><strong>OpenPGP for XMPP</strong> (XEP-0373) using Emacs&rsquo; built-in EPG</li>
<li><strong>Stream Management</strong> (XEP-0198) with session resume</li>
<li><strong>Message Archive Management</strong> (XEP-0313)</li>
<li><strong>Message Carbons</strong> (XEP-0280)</li>
<li><strong>Delivery Receipts</strong> (XEP-0184) and <strong>Chat Markers</strong> (XEP-0333)</li>
<li><strong>Message Correction</strong> (XEP-0308), <strong>Replies</strong> (XEP-0461), <strong>Moderation</strong> (XEP-0424/0425)</li>
<li><strong>Chat State Notifications</strong> (XEP-0085)</li>
<li><strong>Client State Indication</strong> (XEP-0352)</li>
<li><strong>Blocking Command</strong> (XEP-0191)</li>
<li><strong>HTTP File Upload</strong> (XEP-0363)</li>
<li><strong>Direct TLS</strong> (XEP-0368) with dual SRV lookup</li>
<li><strong>Real Time Text</strong> (XEP-0301)</li>
<li><strong>PubSub</strong> (XEP-0060)</li>
<li><strong>Bookmarks</strong> (XEP-0402 with XEP-0048 fallback)</li>
<li><strong>SQLite message storage</strong> replacing flat-file history</li>
<li><strong>MUC Self-Ping</strong> (XEP-0410)</li>
</ul>
</blockquote>
<p><em>Almost caught them all</em></p>
<p>No other text-based XMPP client has this level of protocol coverage.
jabber.el now rivals Dino and Gajim, the major graphical clients.</p>
<h2 id="omemo">OMEMO</h2>
<p>OMEMO requires a Signal Protocol implementation.  That means C.</p>
<p><code>jabber-omemo-core.c</code> is 763 lines wrapping <a href="https://github.com/mierenhoop/picomemo">picomemo</a> through Emacs'
dynamic module API.  The Elisp layer handles XMPP integration: PubSub
bundle publishing, stanza encryption, session persistence in SQLite, and
trust management.</p>
<p>It also provides AES-256-GCM for OMEMO media sharing (<a href="https://xmpp.org/extensions/xep-0454.html">XEP-0454</a>).</p>
<h2 id="why-emacs">Why Emacs</h2>
<p>Emacs is not just the editor I write jabber.el in.  It is the runtime,
the test harness, and the application.</p>
<p>I develop in the same instance where I chat.  Fix a bug, eval changes,
and the fix is live in my running session.  Seconds, not minutes.</p>
<p>Emacs provides most of what a chat client needs out of the box: SQLite
for storage, GnuTLS for encryption, EPG for OpenPGP, EWOC for list
display, Transient for menus.</p>
<p>Distribution is through <a href="https://elpa.nongnu.org/nongnu/jabber.html">NonGNU ELPA</a>, which handles everything.</p>
<p><code>jabber.el</code> is just an <code>M-x package-install RET jabber RET</code> away from
install.</p>
<h2 id="why-xmpp">Why XMPP</h2>
<p>XMPP is the only federated, open-standard messaging protocol that
works <strong>in practice</strong>.  I use it for all my daily communication.  My
friends are on WhatsApp, Discord and IRC &ndash; gateways bridge these
networks transparently.</p>
<p><strong>One client, one interface, every chat network I need.</strong></p>
<blockquote>
<p>More on the gateway setup I use in a future post.</p>
</blockquote>
<h2 id="what-s-next">What&rsquo;s Next</h2>
<ul>
<li><strong>XEP-0444 Message Reactions</strong></li>
<li><strong>OMEMO 0.8+</strong> (picomemo supports both; the C layer is ready)</li>
<li><strong>Roster rework</strong> &ndash; flat, query-based contact list sorted by activity</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis 0.10: Import Anki, Merge Everything Into One</title>
      <link>https://thanosapollo.org/posts/gnosis-8-to-10/</link>
      <pubDate>Sat, 04 Apr 2026 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-8-to-10/</guid>
      <description>&lt;p&gt;&lt;strong&gt;You can now import Anki decks into gnosis.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The entire Anki ecosystem, thousands of community-maintained decks
across every subject, is accessible from Emacs.  I can finally keep
track of the &lt;a href=&#34;https://www.ankihub.net/step-deck&#34;&gt;AnKing&lt;/a&gt; deck changes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you can&amp;rsquo;t beat them, import them.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;anki-import&#34;&gt;Anki import&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;gnosis-anki-import&lt;/code&gt; reads &lt;code&gt;.apkg&lt;/code&gt; files and converts them into gnosis
themata.  It resolves Anki&amp;rsquo;s note type templates to extract
question/answer pairs, normalizes tags, and strips Anki system tags
like &lt;code&gt;marked&lt;/code&gt; and &lt;code&gt;leech&lt;/code&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>You can now import Anki decks into gnosis.</strong></p>
<p>The entire Anki ecosystem, thousands of community-maintained decks
across every subject, is accessible from Emacs.  I can finally keep
track of the <a href="https://www.ankihub.net/step-deck">AnKing</a> deck changes.</p>
<blockquote>
<p><em>If you can&rsquo;t beat them, import them.</em></p>
</blockquote>
<h2 id="anki-import">Anki import</h2>
<p><code>gnosis-anki-import</code> reads <code>.apkg</code> files and converts them into gnosis
themata.  It resolves Anki&rsquo;s note type templates to extract
question/answer pairs, normalizes tags, and strips Anki system tags
like <code>marked</code> and <code>leech</code>.</p>
<p>Re-importing the same deck is safe.  Each imported note keeps its
Anki GUID, so gnosis detects duplicates and skips them.  When AnKing
pushes an update, I just re-import and only the new notes come in.</p>
<blockquote>
<p><em>Tens of thousands of notes &amp; themata, managed from a text editor.</em>
<em>As it should be.</em></p>
</blockquote>
<h2 id="one-package-one-database">One package, one database</h2>
<p><code>org-gnosis</code> was merged into gnosis.  Maintaining two packages with
two databases for what is fundamentally one system was, in retrospect,
an act of bureaucratic self-harm.  Nodes, journal, and themata now
share a single <code>gnosis.db</code>.  The migration imports existing org-gnosis
data automatically.</p>
<h2 id="export-and-import">Export and import</h2>
<p>The old org-file export format is gone.  Exports are now <code>.gnosis</code>
SQLite databases.  Importing shows a diff buffer with NEW and CHANGED
entries before applying, so you see exactly what will change before
committing.</p>
<p>Combined with GUID tracking, this makes gnosis collections
maintainable over time rather than one-shot imports.  Share a deck
with a friend, they modify it, you re-import.  No data lost, no
duplicates.</p>
<h2 id="other">Other</h2>
<ul>
<li>Decks were removed.  They were a restriction, not a feature.
Existing deck names were converted into tags.</li>
<li>N+1 queries eliminated throughout the codebase.</li>
<li>Dashboard rendering is 3-4x faster via a custom <code>gnosis-tl</code> module.</li>
<li>Review dates stored as integers; due/overdue queries run in SQL.</li>
<li>Git operations are fully async.</li>
<li>Saving <code>.org.gpg</code> files no longer triggers redundant decryption.</li>
<li>Post-failure interval capped at 7 days.</li>
<li>Interval fuzz prevents review clustering.</li>
<li>Tag bulk operations: rename, regex rename, merge case duplicates.</li>
<li>Dropped emacsql for built-in sqlite.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis: Design Mistakes</title>
      <link>https://thanosapollo.org/posts/gnosis-packages-merge/</link>
      <pubDate>Sun, 08 Mar 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-packages-merge/</guid>
      <description>&lt;p&gt;The more I use gnosis, the more I notice design faults inherited from
the software I was previously using.&lt;/p&gt;
&lt;h2 id=&#34;using-decks-for-themata--flashcards-questions&#34;&gt;Using decks for themata (flashcards/questions)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Decks will be removed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Similarly to Anki, decks provided a restriction, not a feature.  A
thema can only belong to one deck, &lt;em&gt;many-to-one&lt;/em&gt;, while tags are
&lt;em&gt;many-to-many&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Themata in gnosis are already organized based on &lt;code&gt;tags&lt;/code&gt; and you can
customize the review algorithm per tag using
&lt;code&gt;gnosis-algorithm-custom-values&lt;/code&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The more I use gnosis, the more I notice design faults inherited from
the software I was previously using.</p>
<h2 id="using-decks-for-themata--flashcards-questions">Using decks for themata (flashcards/questions)</h2>
<blockquote>
<p>Decks will be removed.</p>
</blockquote>
<p>Similarly to Anki, decks provided a restriction, not a feature.  A
thema can only belong to one deck, <em>many-to-one</em>, while tags are
<em>many-to-many</em>.</p>
<p>Themata in gnosis are already organized based on <code>tags</code> and you can
customize the review algorithm per tag using
<code>gnosis-algorithm-custom-values</code>.</p>
<p>Exports for &ldquo;collections&rdquo; will now be based on tags.  I plan to add
tag filters for exports, e.g <code>+anatomy -clinical</code> to export all
themata tagged with anatomy, excluding clinical.</p>
<h2 id="separating-gnosis-from-org-gnosis-and-org-gnosis-ui">Separating gnosis from org-gnosis and org-gnosis-ui</h2>
<blockquote>
<p><code>org-gnosis</code> will be merged into <code>gnosis</code>, using a single unified
database.</p>
</blockquote>
<p>The idea was to have a minimal note taking system with a separate ui
package that uses the browser, recreating the workflow I had with
org-roam but with support for linking themata to nodes for
topic-specific reviews.</p>
<p>In hindsight, this separation was a design mistake:</p>
<ul>
<li>Using <code>org-gnosis</code> without <code>gnosis</code> has no real benefits.</li>
<li>A separate <code>org-gnosis-ui</code> that recreates an obsidian-style graph
in the browser provides no real benefit beyond &ldquo;visualizing&rdquo; the
collection.
<ul>
<li>Using <code>tabulated-list</code> in emacs to display nodes, their
backlinks/links and their linked themata provides actual workflow
usage.  You can start reviews for specific nodes from the
dashboard, filter for contents and view relations, all within
emacs.</li>
</ul>
</li>
<li>Maintaining two separate databases for no real value.</li>
</ul>
<h2 id="review-by-topic-algorithm">Review by topic algorithm</h2>
<p>Gnosis supports reviewing all themata linked to a specific node, which
means themata are often reviewed before they are due.  The interval
calculation now uses elapsed time as the basis, but on success keeps
the later of the computed/existing scheduled date.  The thema&rsquo;s score
and review streak are still updated, so early reviews contribute to
progression without distorting the schedule.</p>
<p>This ensures that early successful reviews cannot inflate <em>or</em> deflate
intervals.  On failure the computed interval is used directly since
early failure is genuinely informative.</p>
<h2 id="new-feature-exporting-themata-with-their-linked-nodes">[New Feature] Exporting themata with their linked nodes</h2>
<p>Gnosis exports will optionally include all the linked nodes for the
exported themata.  This means that current collections, like <a href="https://codeberg.org/thanosapollo/gnosis-unking">Unking</a>,
will provide ready-to-use collections where users can both review
themata and browse the related material.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis 0.8.0 Release Notes</title>
      <link>https://thanosapollo.org/posts/gnosis-version-0-8-0/</link>
      <pubDate>Thu, 05 Mar 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-version-0-8-0/</guid>
      <description>Gnosis 0.8.0 Release Overview</description>
      <content:encoded><![CDATA[<p>I&rsquo;m excited to announce the release of version 0.8.0 for <a href="/projects/gnosis/">gnosis</a>.</p>
<p>Finally this project is now evolving into the <em>&ldquo;all-in-one&rdquo;</em> knowledge
system I&rsquo;ve envisioned.  This version allows for viewing of linked
nodes of <code>org-gnosis</code> and their linked themata in a tabulated-list via
the <code>gnosis-dashboard</code> with excellent performance.</p>
<p>No more external browsers needed to view my collection.  This means
the <code>org-gnosis-ui</code> project should be considered deprecated.  All
functionalities can now be performed within Emacs.</p>
<p>Additionally, I&rsquo;ve published a <code>gnosis-deck</code> specifically designed for
fellow medical students, called <a href="https://codeberg.org/thanosapollo/gnosis-unking">Unking</a>, based on the <strong>last free
version</strong> of the <a href="https://www.ankihub.net/step-deck">Anking deck</a>, Anking V11.  This deck is quite
comprehensive, featuring over 40,000 themata.</p>
<p>As Gnosis already fulfills my original intentions and beyond, further
development will primarily be focused on bug fixes and general
maintenance rather than new major features.  My priority will now
shift towards using the system for my exams rather than continuing
active development.</p>
<p>It has been really fun and rewarding working on this project.  My goal
for learning to program has been to make a knowledge system and to not
rely on any 3rd parties for my studying.</p>
<p>Which I&rsquo;ve finally achieved:) This wouldn&rsquo;t be possible without all
the work that many of you have put into the Emacs ecosystem, so I just
want to I extend my heartfelt gratitude to all of you, thank you!</p>
<h2 id="new-features">New features</h2>
<ul>
<li>Auto input-method detection: gnosis detects the script of the
expected answer (Greek, Cyrillic, etc.) and activates the
appropriate input method during review.
Configured via <code>gnosis-script-input-method-alist</code>.</li>
<li>Change thema type and deck via <code>gnosis-update-thema</code>.</li>
<li>Dashboard bulk-link action for currently displayed themata.</li>
<li>Dashboard header-line with entry count and context.</li>
<li>Asynchronous deck import with <code>gnosis-import-deck-async</code>.</li>
<li>Demo deck included in <code>decks/demo.org</code>.</li>
</ul>
<h2 id="performance">Performance</h2>
<ul>
<li>New <code>gnosis-tl</code> module replaces <code>tabulated-list-print</code> for
dashboard rendering (3-4x faster).</li>
<li>Progressive async rendering for large dashboards.</li>
<li>Batch-fetch review data instead of per-thema queries.</li>
</ul>
<h2 id="bug-fixes">Bug fixes</h2>
<ul>
<li>Fix anagnosis event calculation in the algorithm.</li>
<li>Fix cloze tag removal for edge cases and mc-cloze type.</li>
<li>Fix <code>vc-pull</code> to run migrations after pull.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Patrologia Graeca: 1500&#43; Greek Patristic Texts, Free and Open.</title>
      <link>https://thanosapollo.org/posts/patrologia-graeca-bebliotheca/</link>
      <pubDate>Wed, 04 Mar 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/patrologia-graeca-bebliotheca/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been looking for Patristic content for my &lt;a href=&#34;https://bebliotheca.thanosapollo.org&#34;&gt;Bebliotheca&lt;/a&gt; project, a
digital recreation of the library of Constantinople.  My best bet was
finding the work of &lt;a href=&#34;https://en.wikipedia.org/wiki/Patrologia_Graeca&#34;&gt;Migne&amp;rsquo;s Patrologia Graeca&lt;/a&gt; but almost no &lt;em&gt;free&lt;/em&gt;
sources have the original Greek text in proper condition.&lt;/p&gt;
&lt;p&gt;Fortunately, professor &lt;a href=&#34;https://en.wikipedia.org/wiki/Anthony_Kaldellis&#34;&gt;Antonios Kaldellis&lt;/a&gt; offered guidance by pointing
me to a mirror of a now dead project from the &lt;strong&gt;University of the
Aegean&lt;/strong&gt;, for which I found an archive &lt;a href=&#34;https://web.archive.org/web/20070917124937/http://patrologia.ct.aegean.gr/&#34;&gt;here&lt;/a&gt;.  This project contains 143
of the 161 volumes of &lt;a href=&#34;https://en.wikipedia.org/wiki/Patrologia_Graeca&#34;&gt;Migne&amp;rsquo;s Patrologia Graeca&lt;/a&gt;, in perfect condition.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve been looking for Patristic content for my <a href="https://bebliotheca.thanosapollo.org">Bebliotheca</a> project, a
digital recreation of the library of Constantinople.  My best bet was
finding the work of <a href="https://en.wikipedia.org/wiki/Patrologia_Graeca">Migne&rsquo;s Patrologia Graeca</a> but almost no <em>free</em>
sources have the original Greek text in proper condition.</p>
<p>Fortunately, professor <a href="https://en.wikipedia.org/wiki/Anthony_Kaldellis">Antonios Kaldellis</a> offered guidance by pointing
me to a mirror of a now dead project from the <strong>University of the
Aegean</strong>, for which I found an archive <a href="https://web.archive.org/web/20070917124937/http://patrologia.ct.aegean.gr/">here</a>.  This project contains 143
of the 161 volumes of <a href="https://en.wikipedia.org/wiki/Patrologia_Graeca">Migne&rsquo;s Patrologia Graeca</a>, in perfect condition.</p>
<blockquote>
<p>You can get the pdfs from the University of the Aegean project <a href="/pg-migne.tar.gz">here</a> as
<code>tar.gz</code> hosted by me.</p>
</blockquote>
<p>I&rsquo;ve now added these texts to Bebliotheca, under the
<code>#patristic</code> tag.  I will be manually adjusting the titles to a proper
Koine Greek translation to follow along the theme of <em>&ldquo;Library of Constantinople&rdquo;</em></p>
<h2 id="current-corpus-statistics-of-bebliotheca">Current Corpus Statistics of Bebliotheca</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>CORPUS STATISTICS:
</span></span><span style="display:flex;"><span>  Total unique works:       2690
</span></span><span style="display:flex;"><span>  Greek texts:              2316
</span></span><span style="display:flex;"><span>  English translations:     757
</span></span><span style="display:flex;"><span>  Latin texts:              374
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>TRANSLATION COVERAGE:
</span></span><span style="display:flex;"><span>  Greek with English:       571 (24%)
</span></span><span style="display:flex;"><span>  Greek with Latin:         0 (0%)
</span></span><span style="display:flex;"><span>  All three languages:      0
</span></span><span style="display:flex;"><span>  Greek without translation:1745 (75%)
</span></span><span style="display:flex;"><span>  English-only works:       0
</span></span><span style="display:flex;"><span>  Latin-only works:         188
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Gnosis 0.7.0 Release Notes</title>
      <link>https://thanosapollo.org/posts/gnosis-version-0-7-0/</link>
      <pubDate>Sun, 22 Feb 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-version-0-7-0/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve finally published Gnosis version &lt;code&gt;0.7.0&lt;/code&gt; that brings some much
needed changes and integration with &lt;a href=&#34;https://thanosapollo.org/projects/gnosis/&#34;&gt;org-gnosis&lt;/a&gt;.  You can get the
latest version of gnosis via &lt;a href=&#34;https://elpa.gnu.org/packages/gnosis.html&#34;&gt;GNU ELPA&lt;/a&gt; or directly from &lt;a href=&#34;https://git.thanosapollo.org/gnosis/&#34;&gt;upstream&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;new-features&#34;&gt;New features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Review topic from dashboard nodes view (&lt;code&gt;r&lt;/code&gt;), with configurable
forward-link and backlink depth (&lt;code&gt;R&lt;/code&gt; or &lt;code&gt;C-u r&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gnosis-review-topic&lt;/code&gt; accepts separate forward/backlink depth to
include themata from related nodes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gnosis-save-hook&lt;/code&gt; runs after saving a thema, called with the
thema ID.&lt;/li&gt;
&lt;li&gt;Link integrity detection and repair commands
(&lt;code&gt;gnosis-links-check&lt;/code&gt;, &lt;code&gt;gnosis-links-sync&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Dashboard maintenance menu for syncing/rebuilding nodes and link
health checks.&lt;/li&gt;
&lt;li&gt;Dashboard shows themata with orphaned links.&lt;/li&gt;
&lt;li&gt;View due org-gnosis nodes linked to themata from dashboard.&lt;/li&gt;
&lt;li&gt;Bulk replace string in keimenon with org-gnosis node link.&lt;/li&gt;
&lt;li&gt;Custom &lt;code&gt;gnosis-center-content-during-review&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Delete action available during review.&lt;/li&gt;
&lt;li&gt;Format org-gnosis links in keimenon during review output.&lt;/li&gt;
&lt;li&gt;Export deck option to include or exclude suspended themata.&lt;/li&gt;
&lt;li&gt;Exported decks include a &lt;code&gt;#+THEMATA:&lt;/code&gt; header with thema count.&lt;/li&gt;
&lt;li&gt;Importing into an existing deck prompts for confirmation.&lt;/li&gt;
&lt;li&gt;Failed thema imports report the source file line number.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;dashboard&#34;&gt;Dashboard&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Added nodes dashboard, view org-gnosis nodes information including
backlinks and linked themata as well as start a review session.&lt;/li&gt;
&lt;li&gt;Suspend column displays &lt;code&gt;Yes&lt;/code&gt; &lt;code&gt;No&lt;/code&gt; instead of &lt;code&gt;1&lt;/code&gt; &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Flatten Actions submenu into the home menu.&lt;/li&gt;
&lt;li&gt;Separate Import/Export into its own menu column.&lt;/li&gt;
&lt;li&gt;Four-column layout: Navigate, Actions, Import/Export, Maintenance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;algorithm&#34;&gt;Algorithm&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cap gnosis-synolon at &lt;code&gt;gnosis-algorithm-synolon-max&lt;/code&gt; (default 3.0),
floor at 1.3.&lt;/li&gt;
&lt;li&gt;Add interval fuzz to prevent review clustering.&lt;/li&gt;
&lt;li&gt;Fix lethe event: properly reduce gnosis-plus on consecutive failures.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;performance&#34;&gt;Performance&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dashboard suspend, delete, and edit update only the affected entry
instead of refreshing the entire buffer.&lt;/li&gt;
&lt;li&gt;Dashboard nodes view uses bulk queries for link counts (2 queries
instead of 2N).&lt;/li&gt;
&lt;li&gt;Deck export uses 2 bulk queries instead of 2 per thema (N+1 eliminated).&lt;/li&gt;
&lt;li&gt;Deck export uses plain text insertion instead of per-thema buffer scans (O(n^2) eliminated).&lt;/li&gt;
&lt;li&gt;Deck import wraps all operations in a single transaction with
pre-cached IDs (10K fsyncs reduced to 1).&lt;/li&gt;
&lt;li&gt;Review updates use a single DB query.&lt;/li&gt;
&lt;li&gt;Tag output uses a single DB call.&lt;/li&gt;
&lt;li&gt;Average daily reviews computed with a single DB call.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;bug-fixes&#34;&gt;Bug fixes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fix &lt;code&gt;gnosis-monkeytype&lt;/code&gt; hook leak (now buffer-local).&lt;/li&gt;
&lt;li&gt;Fix &lt;code&gt;vc-pull&lt;/code&gt; to reopen database properly after successful pull.&lt;/li&gt;
&lt;li&gt;Pre-load &lt;code&gt;emacsql-sqlite-builtin&lt;/code&gt; to fix &lt;code&gt;cl-generic&lt;/code&gt; dispatch crash
on Emacs 29+.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;documentation&#34;&gt;Documentation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Update Introduction to describe the intended workflow with &lt;code&gt;org-gnosis&lt;/code&gt;
(write notes, create themata, link, review).&lt;/li&gt;
&lt;li&gt;Document the two separate databases (gnosis and org-gnosis).&lt;/li&gt;
&lt;li&gt;Update dashboard section for new menu layout.&lt;/li&gt;
&lt;li&gt;Add Import &amp;amp; Export section with export options and import behavior.&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve finally published Gnosis version <code>0.7.0</code> that brings some much
needed changes and integration with <a href="/projects/gnosis/">org-gnosis</a>.  You can get the
latest version of gnosis via <a href="https://elpa.gnu.org/packages/gnosis.html">GNU ELPA</a> or directly from <a href="https://git.thanosapollo.org/gnosis/">upstream</a>.</p>
<h2 id="new-features">New features</h2>
<ul>
<li>Review topic from dashboard nodes view (<code>r</code>), with configurable
forward-link and backlink depth (<code>R</code> or <code>C-u r</code>).</li>
<li><code>gnosis-review-topic</code> accepts separate forward/backlink depth to
include themata from related nodes.</li>
<li><code>gnosis-save-hook</code> runs after saving a thema, called with the
thema ID.</li>
<li>Link integrity detection and repair commands
(<code>gnosis-links-check</code>, <code>gnosis-links-sync</code>).</li>
<li>Dashboard maintenance menu for syncing/rebuilding nodes and link
health checks.</li>
<li>Dashboard shows themata with orphaned links.</li>
<li>View due org-gnosis nodes linked to themata from dashboard.</li>
<li>Bulk replace string in keimenon with org-gnosis node link.</li>
<li>Custom <code>gnosis-center-content-during-review</code> option.</li>
<li>Delete action available during review.</li>
<li>Format org-gnosis links in keimenon during review output.</li>
<li>Export deck option to include or exclude suspended themata.</li>
<li>Exported decks include a <code>#+THEMATA:</code> header with thema count.</li>
<li>Importing into an existing deck prompts for confirmation.</li>
<li>Failed thema imports report the source file line number.</li>
</ul>
<h2 id="dashboard">Dashboard</h2>
<ul>
<li>Added nodes dashboard, view org-gnosis nodes information including
backlinks and linked themata as well as start a review session.</li>
<li>Suspend column displays <code>Yes</code> <code>No</code> instead of <code>1</code> <code>0</code>.</li>
<li>Flatten Actions submenu into the home menu.</li>
<li>Separate Import/Export into its own menu column.</li>
<li>Four-column layout: Navigate, Actions, Import/Export, Maintenance.</li>
</ul>
<h2 id="algorithm">Algorithm</h2>
<ul>
<li>Cap gnosis-synolon at <code>gnosis-algorithm-synolon-max</code> (default 3.0),
floor at 1.3.</li>
<li>Add interval fuzz to prevent review clustering.</li>
<li>Fix lethe event: properly reduce gnosis-plus on consecutive failures.</li>
</ul>
<h2 id="performance">Performance</h2>
<ul>
<li>Dashboard suspend, delete, and edit update only the affected entry
instead of refreshing the entire buffer.</li>
<li>Dashboard nodes view uses bulk queries for link counts (2 queries
instead of 2N).</li>
<li>Deck export uses 2 bulk queries instead of 2 per thema (N+1 eliminated).</li>
<li>Deck export uses plain text insertion instead of per-thema buffer scans (O(n^2) eliminated).</li>
<li>Deck import wraps all operations in a single transaction with
pre-cached IDs (10K fsyncs reduced to 1).</li>
<li>Review updates use a single DB query.</li>
<li>Tag output uses a single DB call.</li>
<li>Average daily reviews computed with a single DB call.</li>
</ul>
<h2 id="bug-fixes">Bug fixes</h2>
<ul>
<li>Fix <code>gnosis-monkeytype</code> hook leak (now buffer-local).</li>
<li>Fix <code>vc-pull</code> to reopen database properly after successful pull.</li>
<li>Pre-load <code>emacsql-sqlite-builtin</code> to fix <code>cl-generic</code> dispatch crash
on Emacs 29+.</li>
</ul>
<h2 id="documentation">Documentation</h2>
<ul>
<li>Update Introduction to describe the intended workflow with <code>org-gnosis</code>
(write notes, create themata, link, review).</li>
<li>Document the two separate databases (gnosis and org-gnosis).</li>
<li>Update dashboard section for new menu layout.</li>
<li>Add Import &amp; Export section with export options and import behavior.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Org Gnosis 0.2.0 Release Notes</title>
      <link>https://thanosapollo.org/posts/org-gnosis-version-0.2.0/</link>
      <pubDate>Sun, 22 Feb 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-version-0.2.0/</guid>
      <description>&lt;p&gt;I just pushed a new version for &lt;a href=&#34;https://thanosapollo.org/projects/gnosis/&#34;&gt;org-gnosis&lt;/a&gt;, the note taking module of
&lt;a href=&#34;https://thanosapollo.org/projects/gnosis/&#34;&gt;gnosis&lt;/a&gt;, which you can find &lt;a href=&#34;https://git.thanosapollo.org/org-gnosis/&#34;&gt;here&lt;/a&gt;.  The update should be available to
all users via &lt;a href=&#34;https://elpa.gnu.org/packages/org-gnosis.html&#34;&gt;GNU ELPA&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;important-changes&#34;&gt;Important Changes&lt;/h2&gt;
&lt;h3 id=&#34;database-changes&#34;&gt;Database Changes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Database version bumped to 3, tracking &lt;code&gt;mtime&lt;/code&gt; and &lt;code&gt;hash&lt;/code&gt; for both
nodes and journal files.&lt;/li&gt;
&lt;li&gt;Automatic database migration prompts when schema is outdated.&lt;/li&gt;
&lt;li&gt;Lazy database initialization - database connections are created only
when needed, improving startup time.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;org-gnosis-database-file&lt;/code&gt; custom variable to specify custom
database file location.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;performance-improvements&#34;&gt;Performance Improvements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Major performance improvements for &lt;code&gt;org-gnosis-db-sync&lt;/code&gt; with GC
optimization during sync.&lt;/li&gt;
&lt;li&gt;Two-tier incremental sync: fast &lt;code&gt;mtime&lt;/code&gt; check, then accurate &lt;code&gt;hash&lt;/code&gt;
comparison.
&lt;ul&gt;
&lt;li&gt;Only processes files where both modification time and content have
changed.&lt;/li&gt;
&lt;li&gt;Dramatically improves performance for .gpg encrypted files and
large repositories.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Both node files and journal files now use incremental sync with
progress reporting showing changed/total file counts.&lt;/li&gt;
&lt;li&gt;To force full resync, call &lt;code&gt;org-gnosis-db-sync&lt;/code&gt; with prefix arg
&lt;code&gt;C-u&lt;/code&gt;. e.g &lt;code&gt;C-u M-x org-gnosis-db-sync RET&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;journaling&#34;&gt;Journaling&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;By default, today&amp;rsquo;s journal entries are created in
&lt;code&gt;org-gnosis-journal-file&lt;/code&gt; as level 1 headings.
&lt;ul&gt;
&lt;li&gt;When set to &lt;code&gt;nil&lt;/code&gt;, creates separate files for each date entry.&lt;/li&gt;
&lt;li&gt;Creating new entries (e.g., via &lt;code&gt;org-gnosis-journal-find&lt;/code&gt; for an
event, non-date) creates separate files in &lt;code&gt;org-gnosis-journal-dir&lt;/code&gt;
regardless of this setting.&lt;/li&gt;
&lt;li&gt;Single journal file is only used for today&amp;rsquo;s date entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;org-gnosis-journal-as-gpg&lt;/code&gt; that when non-nil journal files
will be created as &lt;code&gt;gpg&lt;/code&gt; encrypted files.&lt;/li&gt;
&lt;li&gt;Journal todos now only retrieve checkboxes from today&amp;rsquo;s heading when
using a single journal file, improving performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;tag-management&#34;&gt;Tag Management&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Automatic cleanup of orphaned tags (tags with no associated nodes)
when updating files.&lt;/li&gt;
&lt;li&gt;Improved tag-based node selection with dedicated functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;improvements&#34;&gt;Improvements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Simplified parsing algorithm for better performance and
maintainability.&lt;/li&gt;
&lt;li&gt;Better handling of topic titles - only includes parent headings when
they have IDs.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;org-gnosis-get-nodes-data&lt;/code&gt; for retrieving node information
with backlink counts.&lt;/li&gt;
&lt;li&gt;Improved test coverage for parsing, title processing, and journal
todos.&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded><![CDATA[<p>I just pushed a new version for <a href="/projects/gnosis/">org-gnosis</a>, the note taking module of
<a href="/projects/gnosis/">gnosis</a>, which you can find <a href="https://git.thanosapollo.org/org-gnosis/">here</a>.  The update should be available to
all users via <a href="https://elpa.gnu.org/packages/org-gnosis.html">GNU ELPA</a>.</p>
<h2 id="important-changes">Important Changes</h2>
<h3 id="database-changes">Database Changes</h3>
<ul>
<li>Database version bumped to 3, tracking <code>mtime</code> and <code>hash</code> for both
nodes and journal files.</li>
<li>Automatic database migration prompts when schema is outdated.</li>
<li>Lazy database initialization - database connections are created only
when needed, improving startup time.</li>
<li>Added <code>org-gnosis-database-file</code> custom variable to specify custom
database file location.</li>
</ul>
<h3 id="performance-improvements">Performance Improvements</h3>
<ul>
<li>Major performance improvements for <code>org-gnosis-db-sync</code> with GC
optimization during sync.</li>
<li>Two-tier incremental sync: fast <code>mtime</code> check, then accurate <code>hash</code>
comparison.
<ul>
<li>Only processes files where both modification time and content have
changed.</li>
<li>Dramatically improves performance for .gpg encrypted files and
large repositories.</li>
</ul>
</li>
<li>Both node files and journal files now use incremental sync with
progress reporting showing changed/total file counts.</li>
<li>To force full resync, call <code>org-gnosis-db-sync</code> with prefix arg
<code>C-u</code>. e.g <code>C-u M-x org-gnosis-db-sync RET</code>.</li>
</ul>
<h3 id="journaling">Journaling</h3>
<ul>
<li>By default, today&rsquo;s journal entries are created in
<code>org-gnosis-journal-file</code> as level 1 headings.
<ul>
<li>When set to <code>nil</code>, creates separate files for each date entry.</li>
<li>Creating new entries (e.g., via <code>org-gnosis-journal-find</code> for an
event, non-date) creates separate files in <code>org-gnosis-journal-dir</code>
regardless of this setting.</li>
<li>Single journal file is only used for today&rsquo;s date entries.</li>
</ul>
</li>
<li>Added <code>org-gnosis-journal-as-gpg</code> that when non-nil journal files
will be created as <code>gpg</code> encrypted files.</li>
<li>Journal todos now only retrieve checkboxes from today&rsquo;s heading when
using a single journal file, improving performance.</li>
</ul>
<h3 id="tag-management">Tag Management</h3>
<ul>
<li>Automatic cleanup of orphaned tags (tags with no associated nodes)
when updating files.</li>
<li>Improved tag-based node selection with dedicated functions.</li>
</ul>
<h2 id="improvements">Improvements</h2>
<ul>
<li>Simplified parsing algorithm for better performance and
maintainability.</li>
<li>Better handling of topic titles - only includes parent headings when
they have IDs.</li>
<li>Added <code>org-gnosis-get-nodes-data</code> for retrieving node information
with backlink counts.</li>
<li>Improved test coverage for parsing, title processing, and journal
todos.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>(Video) Contributing to Git Projects with Magit: PRs, Patches &amp; Agit workflow</title>
      <link>https://thanosapollo.org/posts/video-contributing-with-git-guide/</link>
      <pubDate>Fri, 06 Feb 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/video-contributing-with-git-guide/</guid>
      <description>&lt;center&gt;
&lt;p&gt;&lt;i&gt;Contributing to Git Projects with Magit: PRs, Patches &amp; Agit workflow&lt;/i&gt;&lt;p&gt;
&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/qSHw7D_88-0?si=v248FB_QuJLrabyu&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/center&gt;
&lt;p&gt;Quick video guide on contributing to git projects using Magit.
Showing an overview of the 3 most commonly used workflows&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pull Requests&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agit Workflow&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Git patches&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Video notes:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m creating this as a tutorial video on how to contribute to
&lt;a href=&#34;https://codeberg.org/bebliotheca/bebliotheca&#34;&gt;bebliotheca&lt;/a&gt;, a &lt;em&gt;digital recreation&lt;/em&gt; of the Library of Constantinople to
host texts that would have been found there during the Greco-Roman
Empire.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<center>
<p><i>Contributing to Git Projects with Magit: PRs, Patches & Agit workflow</i><p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/qSHw7D_88-0?si=v248FB_QuJLrabyu" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<p>Quick video guide on contributing to git projects using Magit.
Showing an overview of the 3 most commonly used workflows</p>
<ul>
<li>
<p>Pull Requests</p>
</li>
<li>
<p>Agit Workflow</p>
</li>
<li>
<p>Git patches</p>
<blockquote>
<p>Video notes:</p>
</blockquote>
</li>
</ul>
<h2 id="introduction">Introduction</h2>
<blockquote>
<p>I&rsquo;m creating this as a tutorial video on how to contribute to
<a href="https://codeberg.org/bebliotheca/bebliotheca">bebliotheca</a>, a <em>digital recreation</em> of the Library of Constantinople to
host texts that would have been found there during the Greco-Roman
Empire.</p>
<p>The steps demonstrated here are applicable to any project.</p>
</blockquote>
<p>This is a video guide on contributing to git projects, using Emacs and
Magit (<em>the magical Git client</em>).  <code>Magit</code> provides the best
experience out of the box for a text based interface to git, which
makes <code>magit</code> an emacs&rsquo; killer feature.</p>
<p>In this video we will start from an example Emacs configuration,
adding a theme and installing Magit.  Afterwards we will see how to
contribute to git projects in 3 ways:</p>
<ul>
<li>Pull Requests</li>
<li><a href="https://forgejo.org/docs/latest/user/agit-support/">Agit Workflow Pull Requests</a>
<ul>
<li>Supported in forgejo instances, such as <code>codeberg</code></li>
</ul>
</li>
<li>Git Patches</li>
</ul>
<blockquote>
<p>I personally use <code>vc</code>, a built-in module.  But that&rsquo;s because I enjoy
tinkering and writing my own scripts for it.  Magit does by default a
lot more that even my ~300 line vc config can do.</p>
</blockquote>
<h2 id="requirements">Requirements</h2>
<p>You will need the following software installed:</p>
<ul>
<li><a href="https://git-scm.com/">git</a></li>
<li><a href="https://www.gnu.org/software/emacs/download.html">GNU Emacs</a> <em>(version &gt;=29.2)</em></li>
</ul>
<p><em>Additionally</em>, ensure you have a pair of <strong>SSH keys</strong> already generated and
set up for your forge.</p>
<h2 id="emacs-configuration-i-will-be-using">Emacs Configuration I will be using</h2>
<p>Example <code>init.el</code> file that I will be using:</p>
<ul>
<li>Defaults locations for <code>init.el</code>, depending on your system:
<ul>
<li>GNU/Linux: <code>~/.emacs.d/init.el</code></li>
<li>Windows: <code>C:\Users\&lt;YourUsername&gt;\.emacs.d\init.el</code></li>
</ul>
</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Init packages</span>
</span></span><span style="display:flex;"><span>(package-initialize)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;;; Do not install keycast as well, I&#39;m only using it to share my</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;;; keystrokes for the video.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; (use-package keycast</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;  :ensure t)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Set and load custom.el</span>
</span></span><span style="display:flex;"><span>(setf custom-file (locate-user-emacs-file <span style="color:#e6db74">&#34;custom.el&#34;</span>))
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">load</span> custom-file <span style="color:#e6db74">&#39;noerror</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Completions</span>
</span></span><span style="display:flex;"><span>(fido-vertical-mode <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>(electric-pair-mode <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;; Theming ;;;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(column-number-mode)
</span></span><span style="display:flex;"><span>(global-display-line-numbers-mode <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>(tool-bar-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(tooltip-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(menu-bar-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(blink-cursor-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(scroll-bar-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(set-fringe-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Add transparency</span>
</span></span><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;default-frame-alist</span> <span style="color:#f92672">&#39;</span>(alpha-background <span style="color:#f92672">.</span> <span style="color:#ae81ff">85</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; ef-themes package provides a great theme collection, made by Protesilaos.</span>
</span></span><span style="display:flex;"><span>(use-package ef-themes
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(defun thanos/load-theme (<span style="color:#66d9ef">&amp;optional</span> theme)
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Disable current theme and load a new THEME.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Emacs can load multiple themes at once.  With this function we make sure we only load one at a time&#34;</span>
</span></span><span style="display:flex;"><span>  (interactive)
</span></span><span style="display:flex;"><span>  (let ((theme (or theme (<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">completing-read</span> <span style="color:#e6db74">&#34;Theme: &#34;</span> (custom-available-themes))))))
</span></span><span style="display:flex;"><span>    (disable-theme (<span style="color:#a6e22e">car</span> custom-enabled-themes))
</span></span><span style="display:flex;"><span>    (load-theme theme <span style="color:#66d9ef">t</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(thanos/load-theme <span style="color:#e6db74">&#39;ef-dark</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(use-package magit
</span></span><span style="display:flex;"><span>  :bind (<span style="color:#e6db74">&#34;C-x g&#34;</span> <span style="color:#f92672">.</span> magit)
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Hook flyspell for autocorrect during commit messages.</span>
</span></span><span style="display:flex;"><span>  :hook (git-commit-mode <span style="color:#f92672">.</span> flyspell-mode))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Agitjo extends Magit with a new menu for AGit-Flow operations.</span>
</span></span><span style="display:flex;"><span>(use-package agitjo
</span></span><span style="display:flex;"><span>  :vc (:url <span style="color:#e6db74">&#34;https://codeberg.org/halvin/agitjo&#34;</span>)
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>)
</span></span></code></pre></div><h2 id="pull-requests">Pull Requests</h2>
<ul>
<li>Require an account creation for the forge the project is hosted at.
<em>e.g Github or Codeberg.</em></li>
<li><strong>Steps to submit a PR</strong>
<ul>
<li><strong>Fork</strong> repository, <em>through a Web UI.</em></li>
<li><strong>Clone</strong> your fork</li>
<li><strong>Commit</strong> changes, <em>often in a new branch.</em></li>
<li><strong>Push</strong> your changes to your fork</li>
<li><strong>Submit</strong> a Pull Request, <em>through a Web UI.</em></li>
</ul>
</li>
</ul>
<blockquote>
<p>If you&rsquo;d rather not use a Web UI, but have to use Pull Requests,
consider using <a href="https://github.com/magit/forge">forge</a>.</p>
</blockquote>
<h2 id="agit-workflow">Agit workflow</h2>
<blockquote>
<p>Note that the <strong>agit workflow</strong> is not supported by GitHub at the time
of making this video.  To use agit workflow, you will need to utilize
a forgejo instance such as Codeberg.</p>
</blockquote>
<ul>
<li>Clone repo, <em>using ssh</em></li>
<li>Commit changes</li>
<li>Push
<ul>
<li>From the Magit status buffer, press <code>#</code></li>
<li>Specify a title using <code>-t</code>
<ul>
<li>You can use the same title to push changes to the PR.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="git-patches">Git patches</h2>
<ul>
<li>Clone repo.</li>
<li>Commit changes.</li>
<li>Format patches.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ git format-patch -<span style="color:#f92672">{</span>NUM<span style="color:#f92672">}</span> <span style="color:#75715e"># where NUM the number of commits.</span>
</span></span></code></pre></div><ul>
<li>Send patches as attachments via email, by pressing <code>C-x C-m</code>.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Cgit with GNU Guix</title>
      <link>https://thanosapollo.org/posts/cgit-guix/</link>
      <pubDate>Sun, 01 Feb 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/cgit-guix/</guid>
      <description>&lt;p&gt;Recently I switched my home server to &lt;a href=&#34;https://guix.gnu.org&#34;&gt;GNU Guix&lt;/a&gt;, this is a quick guide
on how I setup &lt;code&gt;cgit&lt;/code&gt;.  Hope this helps some of you.&lt;/p&gt;
&lt;h2 id=&#34;why-i-use-gnu-guix-for-my-server&#34;&gt;Why I use GNU Guix for my server&lt;/h2&gt;
&lt;p&gt;GNU Guix is my preferred system for every machine I use, recently I
even switched my home server (&lt;em&gt;back&lt;/em&gt;) to Guix.  I use my home server to
host this blog as well as my &lt;a href=&#34;https://git.thanosapollo.org&#34;&gt;cgit instance&lt;/a&gt;, so far I recommend using
Guix, as a hobbyist, for the following reasons:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Recently I switched my home server to <a href="https://guix.gnu.org">GNU Guix</a>, this is a quick guide
on how I setup <code>cgit</code>.  Hope this helps some of you.</p>
<h2 id="why-i-use-gnu-guix-for-my-server">Why I use GNU Guix for my server</h2>
<p>GNU Guix is my preferred system for every machine I use, recently I
even switched my home server (<em>back</em>) to Guix.  I use my home server to
host this blog as well as my <a href="https://git.thanosapollo.org">cgit instance</a>, so far I recommend using
Guix, as a hobbyist, for the following reasons:</p>
<ul>
<li><code>Roll backs</code>
<ul>
<li>I had tried both Gentoo and Debian before for my server, more than
once I had one or more of my self hosted services down because an
update broke my setup.  My time is limited and those breakages
would often occur at busy weeks where I didn&rsquo;t have the time to
fix them.  With Guix I can just roll back to a previous working
generation if an update or a misconfiguration of mine breaks something.</li>
</ul>
</li>
<li><code>Reproducibility</code>
<ul>
<li>Define your setup once, run anywhere.  I do not want to manually
setup anything.</li>
</ul>
</li>
<li><code>Simplicity</code>
<ul>
<li>The entirety of Guix code lives in <a href="https://codeberg.org/guix/guix">one repo</a> and is almost entirely
written in one language, guile scheme.  If you find any issues
with a service or a package you can redefine it as you like in
your configuration.</li>
</ul>
</li>
</ul>
<h2 id="why-self-host-a-git-server">Why self-host a git server?</h2>
<p>Why would you not self-host your own projects?  I find it antithetical
to the FOSS ethos, and perhaps even ironic, to rely on proprietary
platforms for distributing free software.</p>
<p>Hosting a Git server is straightforward and requires minimal resources.</p>
<h2 id="git-http-backend-uri-issue-and-fix">git-http-backend &ldquo;/&rdquo; uri issue and fix</h2>
<p>Guix has a separate configuration data type for serving Git
repositories over HTTP.  Currently, the regex it uses does not allow
the root <code>&quot;/&quot;</code> to be used a URI for serving (<a href="https://lists.gnu.org/archive/html/help-guix/2022-07/msg00002.html">ref archive</a>).</p>
<p>The issue is in the <code>(gnu services version-control)</code> module, specifically in this part:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(define* (git-http-nginx-location-configuration <span style="color:#e6db74">#:optional</span>
</span></span><span style="display:flex;"><span>                                                (config
</span></span><span style="display:flex;"><span>                                                 (git-http-configuration)))
</span></span><span style="display:flex;"><span>  (match config
</span></span><span style="display:flex;"><span>    (($ &lt;git-http-configuration&gt; package git-root export-all?
</span></span><span style="display:flex;"><span>                                 uri-path fcgiwrap-socket)
</span></span><span style="display:flex;"><span>     (nginx-location-configuration
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">;; ISSUE here: regex won&#39;t allow for &#34;/&#34;</span>
</span></span><span style="display:flex;"><span>      (uri (string-append <span style="color:#e6db74">&#34;~ /&#34;</span> (string-trim-both uri-path <span style="color:#960050;background-color:#1e0010">#</span>\/) <span style="color:#e6db74">&#34;(/.*)&#34;</span>))
</span></span><span style="display:flex;"><span>      (body
</span></span><span style="display:flex;"><span>       (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">list</span> <span style="color:#e6db74">&#34;fastcgi_pass &#34;</span> fcgiwrap-socket <span style="color:#e6db74">&#34;;&#34;</span>)
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">list</span> <span style="color:#e6db74">&#34;fastcgi_param SCRIPT_FILENAME &#34;</span>
</span></span><span style="display:flex;"><span>              package <span style="color:#e6db74">&#34;/libexec/git-core/git-http-backend&#34;</span>
</span></span><span style="display:flex;"><span>              <span style="color:#e6db74">&#34;;&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;fastcgi_param QUERY_STRING $query_string;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;fastcgi_param REQUEST_METHOD $request_method;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;fastcgi_param CONTENT_TYPE $content_type;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;fastcgi_param CONTENT_LENGTH $content_length;&#34;</span>
</span></span><span style="display:flex;"><span>        (if export-all?
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;fastcgi_param GIT_HTTP_EXPORT_ALL \&#34;\&#34;;&#34;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">list</span> <span style="color:#e6db74">&#34;fastcgi_param GIT_PROJECT_ROOT &#34;</span> git-root <span style="color:#e6db74">&#34;;&#34;</span>)
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">list</span> <span style="color:#e6db74">&#34;fastcgi_param GIT_CONFIG_GLOBAL &#34;</span>
</span></span><span style="display:flex;"><span>              (plain-file <span style="color:#e6db74">&#34;gitconfig&#34;</span>
</span></span><span style="display:flex;"><span>                          (string-append <span style="color:#e6db74">&#34;[safe]\n\tdirectory = &#34;</span> git-root <span style="color:#e6db74">&#34;/*\n&#34;</span>))
</span></span><span style="display:flex;"><span>              <span style="color:#e6db74">&#34;;&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;fastcgi_param PATH_INFO $1;&#34;</span>))))))
</span></span></code></pre></div><p>Thankfully, we can easily resolve this by redefining
<code>(gnu services version-control)</code>.</p>
<ul>
<li>My changes (diff) to fix this issue, as well as specify git actions:</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm
</span></span><span style="display:flex;"><span>index a7f40812a6c..e33e5de21f0 100644
</span></span><span style="display:flex;"><span><span style="color:#f92672">--- a/gnu/services/version-control.scm
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+++ b/gnu/services/version-control.scm
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span><span style="color:#75715e">@@ -235,7 +235,11 @@ (define* (git-http-nginx-location-configuration #:optional
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>     (($ &lt;git-http-configuration&gt; package git-root export-all?
</span></span><span style="display:flex;"><span>                                  uri-path fcgiwrap-socket)
</span></span><span style="display:flex;"><span>      (nginx-location-configuration
</span></span><span style="display:flex;"><span><span style="color:#f92672">-      (uri (string-append &#34;~ /&#34; (string-trim-both uri-path #\/) &#34;(/.*)&#34;))
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+      (uri (string-append &#34;~ &#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+			  (if (string=? uri-path &#34;/&#34;)
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+                              &#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+                              (string-append &#34;/&#34; (string-trim-both uri-path #\/)))
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+			  &#34;/(info/refs|git-upload-pack|git-receive-pack)&#34;))
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>       (body
</span></span><span style="display:flex;"><span>        (list
</span></span><span style="display:flex;"><span>         (list &#34;fastcgi_pass &#34; fcgiwrap-socket &#34;;&#34;)
</span></span><span style="display:flex;"><span><span style="color:#75715e">@@ -254,7 +258,7 @@ (define* (git-http-nginx-location-configuration #:optional
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>               (plain-file &#34;gitconfig&#34;
</span></span><span style="display:flex;"><span>                           (string-append &#34;[safe]\n\tdirectory = &#34; git-root &#34;/*\n&#34;))
</span></span><span style="display:flex;"><span>               &#34;;&#34;)
</span></span><span style="display:flex;"><span><span style="color:#f92672">-        &#34;fastcgi_param PATH_INFO $1;&#34;))))))
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+        &#34;fastcgi_param PATH_INFO $uri;&#34;))))))
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> ;;;
</span></span></code></pre></div><p>You can find the full module that I use <a href="https://git.thanosapollo.org/dotfiles/tree/guix/services/version-control.scm">here</a> in my dotfiles repo.</p>
<p>I&rsquo;d recommend creating your own module and load it by running the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo guix system reocnfigure ~/dotfiles/guix/server-config.scm -L ~/dotfiles/guix
</span></span></code></pre></div><h2 id="configuring-cgit-service-type">Configuring <code>cgit-service-type</code></h2>
<p>Guix provides a cgit service module <code>(gnu services cgit)</code>.</p>
<blockquote>
<p>A couple things to note:</p>
<ul>
<li>You can provide <code>css</code> and <code>favicon</code> using an external url.  You can
find the css styling that I use <a href="https://thanosapollo.org/cgit.css">here</a>.</li>
</ul>
</blockquote>
<p>Example <code>cgit-service-type</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span>(<span style="color:#66d9ef">define </span>my/git-repos
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>   (<span style="color:#a6e22e">repository-cgit-configuration</span>
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">&#34;repo1&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#34;repo1&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">desc</span> <span style="color:#e6db74">&#34;Example Repo 1&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">path</span> <span style="color:#e6db74">&#34;/srv/git/repo1&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">section</span> <span style="color:#e6db74">&#34;Section 1&#34;</span>))
</span></span><span style="display:flex;"><span>   (<span style="color:#a6e22e">repository-cgit-configuration</span>
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">&#34;repo2&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">&#34;repo2&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">desc</span> <span style="color:#e6db74">&#34;Example Repo 2&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">path</span> <span style="color:#e6db74">&#34;/srv/git/repo2&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">homepage</span> <span style="color:#e6db74">&#34;https://myhomepage&#34;</span>)
</span></span><span style="display:flex;"><span>     (<span style="color:#a6e22e">section</span> <span style="color:#e6db74">&#34;Section 2&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">service</span> cgit-service-type
</span></span><span style="display:flex;"><span>         (<span style="color:#a6e22e">cgit-configuration</span>
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">package</span> cgit)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">root-desc</span> <span style="color:#e6db74">&#34;Root Desc&#34;</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">repository-directory</span> <span style="color:#e6db74">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">root-title</span> <span style="color:#e6db74">&#34;Root Title&#34;</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">repositories</span> my/git-repos)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">enable-index-owner?</span> <span style="color:#66d9ef">#f</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">enable-http-clone?</span> <span style="color:#66d9ef">#f</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">clone-prefix</span> <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;https://git.thanosapollo.org&#34;</span>)) <span style="color:#75715e">;; change this to your own url</span>
</span></span><span style="display:flex;"><span>           <span style="color:#75715e">;; Cache</span>
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-root</span> <span style="color:#e6db74">&#34;/var/cache/cgit&#34;</span>)
</span></span><span style="display:flex;"><span>           <span style="color:#75715e">;; 20000 = 5 hours.  Feel free to adjust this.</span>
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-size</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-static-ttl</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-dynamic-ttl</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-repo-ttl</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-root-ttl</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-scanrc-ttl</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-about-ttl</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">cache-snapshot-ttl</span> <span style="color:#ae81ff">20000</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">case-sensitive-sort?</span> <span style="color:#66d9ef">#f</span>)
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">css</span> <span style="color:#e6db74">&#34;https://thanosapollo.org/cgit.css&#34;</span>) <span style="color:#75715e">;; My personal css.</span>
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">nginx</span>
</span></span><span style="display:flex;"><span>            (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">nginx-server-configuration</span>
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">server-name</span> <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;git.thanosapollo.org&#34;</span>))
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">root</span> cgit)
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">try-files</span> (list <span style="color:#e6db74">&#34;$uri&#34;</span> <span style="color:#e6db74">&#34;@cgit&#34;</span>))
</span></span><span style="display:flex;"><span>               <span style="color:#75715e">;; I use cloudflare tunnel, which handles certs for me.</span>
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">listen</span> <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;80&#34;</span>))
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">ssl-certificate</span> <span style="color:#66d9ef">#f</span>)
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">ssl-certificate-key</span> <span style="color:#66d9ef">#f</span>)
</span></span><span style="display:flex;"><span>               <span style="color:#75715e">;; ;; If you use certbot try the following:</span>
</span></span><span style="display:flex;"><span>               <span style="color:#75715e">;; (listen &#39;(&#34;443 ssl&#34;))</span>
</span></span><span style="display:flex;"><span>               <span style="color:#75715e">;; (ssl-certificate</span>
</span></span><span style="display:flex;"><span>               <span style="color:#75715e">;;  &#34;/etc/certs/git.my-host.org/fullchain.pem&#34;)</span>
</span></span><span style="display:flex;"><span>               <span style="color:#75715e">;; (ssl-certificate-key</span>
</span></span><span style="display:flex;"><span>               <span style="color:#75715e">;;  &#34;/etc/certs/git.my-host.org/privkey.pem&#34;)</span>
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">locations</span>
</span></span><span style="display:flex;"><span>                (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>                 (<span style="color:#a6e22e">nginx-location-configuration</span>
</span></span><span style="display:flex;"><span>                   (<span style="color:#a6e22e">uri</span> <span style="color:#e6db74">&#34;@cgit&#34;</span>)
</span></span><span style="display:flex;"><span>                   (<span style="color:#a6e22e">body</span> <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;fastcgi_param SCRIPT_FILENAME $document_root/lib/cgit/cgit.cgi;&#34;</span>
</span></span><span style="display:flex;"><span>                           <span style="color:#e6db74">&#34;fastcgi_param PATH_INFO $uri;&#34;</span>
</span></span><span style="display:flex;"><span>                           <span style="color:#e6db74">&#34;fastcgi_param QUERY_STRING $args;&#34;</span>
</span></span><span style="display:flex;"><span>                           <span style="color:#e6db74">&#34;fastcgi_param HTTP_HOST $server_name;&#34;</span>
</span></span><span style="display:flex;"><span>                           <span style="color:#e6db74">&#34;fastcgi_pass 127.0.0.1:9000;&#34;</span>)))
</span></span><span style="display:flex;"><span>                 (<span style="color:#a6e22e">git-http-nginx-location-configuration</span>
</span></span><span style="display:flex;"><span>                  (<span style="color:#a6e22e">git-http-configuration</span>
</span></span><span style="display:flex;"><span>                    (<span style="color:#a6e22e">uri-path</span> <span style="color:#e6db74">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span>                    (<span style="color:#a6e22e">export-all?</span> <span style="color:#66d9ef">#t</span>))))))))))
</span></span></code></pre></div><p>You can find my home server configuration <a href="https://git.thanosapollo.org/dotfiles/tree/guix/theodora.scm">here</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>(Video) Emacs Notmuch with Multiple Addresses &amp; Auto Encryption</title>
      <link>https://thanosapollo.org/posts/emacs-notmuch-video-guide/</link>
      <pubDate>Thu, 18 Dec 2025 00:00:00 +0000</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-notmuch-video-guide/</guid>
      <description>Video guide for managing emails with Emacs, using notmuch &amp;amp; isync.</description>
      <content:encoded><![CDATA[<p>This guide provides a quick setup for configuring Notmuch with GNU
Emacs to handle multiple email addresses and enable automatic
encryption.</p>
<p>Notmuch has been incredibly useful for me over the past year, and I
hope this guide helps new users overcome initial challenges.</p>
<center>
<p><i>Emacs Notmuch with Multiple Addresses & Auto Encryption</i><p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/P42C5wEQK-Y?si=wbDx5y3zH5Wd23gE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<blockquote>
<p>Video notes:</p>
</blockquote>
<h2 id="summary">Summary</h2>
<ul>
<li>Emacs email workflow demo using <code>notmuch.el</code>.
<ul>
<li>Sending mails from multiple addresses, using <a href="%5C%2Asmtpmail">smtpmail</a>.</li>
<li>Auto encrypt emails, if a pgp key is available, using <a href="%5C%2Amml-sec">mml-sec</a>.</li>
</ul>
</li>
</ul>
<h2 id="why-notmuch">Why notmuch</h2>
<ul>
<li>Builtin Emacs support, with <code>notmuch.el</code>.
<ul>
<li>Packages such as <a href="https://github.com/tarsius/ol-notmuch">ol-notmuch</a> bring integration with the rest of
the Emacs ecosystem.</li>
</ul>
</li>
<li>Notmuch is a <code>tag based system</code>.  You do not rely on your email
provider for filter rules etc to organize your emails into separate
mailboxes.
<ul>
<li>Which is inefficient to begin with when working with thousands++ of emails.</li>
<li>This also makes moving to a new email provider easier.</li>
</ul>
</li>
<li>Locally storing mail.</li>
<li>Great performance for filtering and searching through hundred of thousand mails.</li>
</ul>
<h2 id="assumptions-that-i-make-for-this-video">Assumptions that I make for this video</h2>
<h3 id="you-have-a-working-emacs-configuration">You have a working Emacs configuration</h3>
<h3 id="your-mail-providers-has-support-for-retrieving-and-sending-mail-via-3rd-party-apps">Your mail providers has support for retrieving and sending mail via 3rd party apps</h3>
<ul>
<li>You already know how to setup <code>isync/mbsync</code> to retrieve emails from remote server.</li>
<li>Your mail provider offers <code>smtp</code> credentials to use third party applications.
<ul>
<li>I personally recommend trying out <code>purelymail.com</code> <strong>only costs 10$/year and offers good service</strong>.</li>
</ul>
</li>
</ul>
<p><em>Example isyncrc configuration</em> <code>~/.config/isyncrc</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#a6e22e">IMAPAccount gmail</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Host imap.gmail.com</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Port 993</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">User user@gmail.com # Change this to your username.</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">PassCmd &#34;pass gmail/account&#34; # Change this to a command that returns your password.</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">TLSType IMAPS</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">TLSVersions +1.2</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">CertificateFile /etc/ssl/certs/ca-certificates.crt</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">IMAPStore gmail-remote</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Account gmail</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">MaildirStore gmail-local</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Path ~/Mail/gmail/</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Inbox ~/Mail/gmail/Inbox</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Trash ~/Mail/gmail/Trash</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">SubFolders Verbatim</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Channel gmail</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Far :gmail-remote:</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Near :gmail-local:</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Patterns *</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Expunge None</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">CopyArrivalDate yes</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Sync All</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Create Both</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">SyncState *</span>
</span></span></code></pre></div><p>After adjusting the above configuration, run <code>mbsync -a</code> to sync your remote mailbox locally.</p>
<h2 id="setting-up-a-notmuch">Setting up a notmuch</h2>
<h3 id="first-time-installation">First time installation</h3>
<ul>
<li>After installing notmuch for the first time, run <code>notmuch setup</code> for an interactive setup.</li>
</ul>
<h3 id="create-dot-scripts-notmuch-hook-dot-sh">Create <code>~/.scripts/notmuch-hook.sh</code></h3>
<ul>
<li>Bash script which will filter/tag your mail</li>
</ul>
<p>Example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>notmuch new
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Add +inbox tag to a specific alias/address</span>
</span></span><span style="display:flex;"><span>notmuch tag +inbox -- to:main@address.org
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#Sent messages, change this to your mail addresses</span>
</span></span><span style="display:flex;"><span>notmuch tag -unread -new -inbox +sent -- from:*@mydomain.org or from:*@mydomain.com or from:user@gmail.com
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Example for Emacs-devel</span>
</span></span><span style="display:flex;"><span>notmuch tag +emacs-devel -new -inbox -- from:emacs-devel@gnu.org or to:emacs-devel@gnu.org
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Example for Github</span>
</span></span><span style="display:flex;"><span>notmuch tag +github -- from:*github.com
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Filter based on other tags, such as drafts</span>
</span></span><span style="display:flex;"><span>notmuch tag -inbox -sent -inbox -- tag:draft
</span></span></code></pre></div><h2 id="emacs-configuration">Emacs configuration</h2>
<h3 id="notmuch">Notmuch</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package notmuch
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (defun thanos/notmuch-update--command (new-buffer)
</span></span><span style="display:flex;"><span>    (let ((default-directory <span style="color:#e6db74">&#34;~/.scripts/&#34;</span>)) <span style="color:#75715e">;; Directory where notmuch script is located.</span>
</span></span><span style="display:flex;"><span>      (async-shell-command <span style="color:#e6db74">&#34;mbsync -a; ./notmuch-hook.sh&#34;</span> new-buffer)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/notmuch-update ()
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (let* ((buffer (generate-new-buffer <span style="color:#e6db74">&#34;*notmuch update*&#34;</span>))
</span></span><span style="display:flex;"><span>           (height (<span style="color:#a6e22e">max</span> <span style="color:#ae81ff">5</span> (<span style="color:#a6e22e">truncate</span> (<span style="color:#a6e22e">*</span> (frame-height) <span style="color:#ae81ff">0.1</span>))))
</span></span><span style="display:flex;"><span>           (window (split-window-vertically (<span style="color:#a6e22e">-</span> height))))
</span></span><span style="display:flex;"><span>      (with-selected-window window
</span></span><span style="display:flex;"><span>        (switch-to-buffer buffer)
</span></span><span style="display:flex;"><span>        (let ((proc (thanos/notmuch-update--command buffer)))
</span></span><span style="display:flex;"><span>          (<span style="color:#a6e22e">set-process-sentinel</span>
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">get-buffer-process</span> buffer)
</span></span><span style="display:flex;"><span>           (lambda (process event)
</span></span><span style="display:flex;"><span>             (when (<span style="color:#a6e22e">memq</span> (<span style="color:#a6e22e">process-status</span> process) <span style="color:#f92672">&#39;</span>(exit <span style="color:#a6e22e">signal</span>))
</span></span><span style="display:flex;"><span>               (delete-window (<span style="color:#a6e22e">get-buffer-window</span> (<span style="color:#a6e22e">process-buffer</span> process)))
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">kill-buffer</span> (<span style="color:#a6e22e">process-buffer</span> process)))))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/notmuch-search ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Custom notmuch-search wrapper, that makes sure we have newest mail first.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (let ((query (notmuch-read-query <span style="color:#e6db74">&#34;Notmuch search: &#34;</span>)))
</span></span><span style="display:flex;"><span>      (notmuch-search query <span style="color:#66d9ef">nil</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Configure saved searches to your liking, here&#39;s an example:</span>
</span></span><span style="display:flex;"><span>  (setf notmuch-saved-searches
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">`</span>((:name <span style="color:#e6db74">&#34;Week&#39;s Inbox&#34;</span> :query <span style="color:#e6db74">&#34;tag:inbox date:7d..today&#34;</span> :sort-order newest-first
</span></span><span style="display:flex;"><span>                 :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;i&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;Inbox&#34;</span> :query <span style="color:#e6db74">&#34;tag:inbox&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;I&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;Unread&#34;</span> :query <span style="color:#e6db74">&#34;tag:unread&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;u&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;Today&#39;s message&#34;</span> :query <span style="color:#e6db74">&#34;tag:inbox date:today&#34;</span>
</span></span><span style="display:flex;"><span>                 :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;t&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;sent&#34;</span> :query <span style="color:#e6db74">&#34;tag:sent&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;s&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;drafts&#34;</span> :query <span style="color:#e6db74">&#34;tag:draft&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;d&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;all mail&#34;</span> :query <span style="color:#e6db74">&#34;*&#34;</span> :sort-order oldest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;a&#34;</span>))))
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Tag format configuration</span>
</span></span><span style="display:flex;"><span>  (setf notmuch-tag-formats
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;unread&#34;</span> (<span style="color:#a6e22e">propertize</span> tag <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;notmuch-tag-unread</span>))))
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-x m&#34;</span> <span style="color:#f92672">.</span> notmuch-hello)
</span></span><span style="display:flex;"><span>         :map notmuch-hello-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;u&#34;</span> <span style="color:#f92672">.</span> notmuch-hello-update)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;U&#34;</span> <span style="color:#f92672">.</span> thanos/notmuch-update)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;s&#34;</span> <span style="color:#f92672">.</span> thanos/notmuch-search)
</span></span><span style="display:flex;"><span>         :map notmuch-search-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;u&#34;</span> <span style="color:#f92672">.</span> notmuch-refresh-all-buffers)))
</span></span></code></pre></div><h3 id="smtpmail">smtpmail</h3>
<ul>
<li>This configuration is used to send email from multiple addresses,
make sure you have your authentication password saved in
<code>~/.authinfo.gpg</code> which emacs is going to use by default.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package smtpmail
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Default credentials</span>
</span></span><span style="display:flex;"><span>  (setf smtpmail-smtp-user (auth-source-pass-get <span style="color:#e6db74">&#34;user&#34;</span> <span style="color:#e6db74">&#34;gmail/user&#34;</span>) <span style="color:#75715e">;; This is not your password, just the username.  Emacs will search for your pw in ~/.authinfo.gpg.</span>
</span></span><span style="display:flex;"><span>        smtpmail-smtp-server <span style="color:#e6db74">&#34;smtp.gmail.com&#34;</span>
</span></span><span style="display:flex;"><span>        smtpmail-smtp-service <span style="color:#ae81ff">465</span> <span style="color:#75715e">;; Adjust this to your mail provider port if needed</span>
</span></span><span style="display:flex;"><span>        smtpmail-stream-type <span style="color:#e6db74">&#39;ssl</span>
</span></span><span style="display:flex;"><span>        message-send-mail-function <span style="color:#e6db74">&#39;smtpmail-send-it</span>
</span></span><span style="display:flex;"><span>        message-signature <span style="color:#e6db74">&#34;My signature&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/mail-config-hook ()
</span></span><span style="display:flex;"><span>    (let ((from (mail-fetch-field <span style="color:#e6db74">&#34;From&#34;</span>))
</span></span><span style="display:flex;"><span>          (public <span style="color:#e6db74">&#34;&lt;public@thanosapollo.org&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>          (gmail <span style="color:#e6db74">&#34;&lt;104111@students.mu-sofia.bg&gt;&#34;</span>))
</span></span><span style="display:flex;"><span>      (cond ((<span style="color:#a6e22e">string-match</span> public from)
</span></span><span style="display:flex;"><span>             (setf smtpmail-smtp-user (auth-source-pass-get <span style="color:#e6db74">&#34;user&#34;</span> <span style="color:#e6db74">&#34;purelymail/thanosapollo&#34;</span>)
</span></span><span style="display:flex;"><span>                   smtpmail-smtp-server <span style="color:#e6db74">&#34;smtp.purelymail.com&#34;</span>))
</span></span><span style="display:flex;"><span>            ((<span style="color:#a6e22e">string-match</span> gmail from)
</span></span><span style="display:flex;"><span>             (setf smtpmail-smtp-user <span style="color:#e6db74">&#34;104111@students.mu-sofia.bg&#34;</span>
</span></span><span style="display:flex;"><span>                   smtpmail-smtp-server <span style="color:#e6db74">&#34;smtp.gmail.com&#34;</span>)))))
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; You can use :hook instead, but I prefer add-hook under :config personally.</span>
</span></span><span style="display:flex;"><span>  (add-hook <span style="color:#e6db74">&#39;message-send-hook</span> <span style="color:#a6e22e">#&#39;</span>thanos/mail-config-hook))
</span></span></code></pre></div><h3 id="mml-sec">mml-sec</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package mml-sec
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (defun gpg-list-emails-available ()
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Return a list of trusted emails.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Parses output of `gpg --list-keys --with-colons&#39; command into a
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">list of emails.&#34;</span>
</span></span><span style="display:flex;"><span>  (let* ((command <span style="color:#e6db74">&#34;gpg --list-keys --with-colons&#34;</span>)
</span></span><span style="display:flex;"><span>         (output (shell-command-to-string command))
</span></span><span style="display:flex;"><span>         (lines (split-string output <span style="color:#e6db74">&#34;\n&#34;</span> <span style="color:#66d9ef">t</span>))
</span></span><span style="display:flex;"><span>         (emails <span style="color:#f92672">&#39;</span>()))
</span></span><span style="display:flex;"><span>    (dolist (line lines)
</span></span><span style="display:flex;"><span>      (when (string-prefix-p <span style="color:#e6db74">&#34;uid:&#34;</span> line)
</span></span><span style="display:flex;"><span>        (when (<span style="color:#a6e22e">string-match</span> <span style="color:#e6db74">&#34;&lt;\\([^&gt;]+\\)&gt;&#34;</span> line)
</span></span><span style="display:flex;"><span>          (let ((email (<span style="color:#a6e22e">downcase</span> (string-trim (match-string <span style="color:#ae81ff">1</span> line)))))
</span></span><span style="display:flex;"><span>            (push email emails)))))
</span></span><span style="display:flex;"><span>    (delete-dups emails)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/mail-list-recipients-from-buffer ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Get the list of recipients from the current email buffer.&#34;</span>
</span></span><span style="display:flex;"><span>    (save-excursion
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">goto-char</span> (<span style="color:#a6e22e">point-min</span>))
</span></span><span style="display:flex;"><span>      (let ((to (or (mail-fetch-field <span style="color:#e6db74">&#34;To&#34;</span>) <span style="color:#e6db74">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>            (cc (or (mail-fetch-field <span style="color:#e6db74">&#34;Cc&#34;</span>) <span style="color:#e6db74">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>            (bcc (or (mail-fetch-field <span style="color:#e6db74">&#34;Bcc&#34;</span>) <span style="color:#e6db74">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>            recipients)
</span></span><span style="display:flex;"><span>        (setq recipients (<span style="color:#a6e22e">concat</span> to <span style="color:#e6db74">&#34;, &#34;</span> cc <span style="color:#e6db74">&#34;, &#34;</span> bcc))
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">;; Remove empty strings from the result</span>
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">delq</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>              (<span style="color:#a6e22e">mapcar</span> (lambda (addr)
</span></span><span style="display:flex;"><span>                        (let ((clean-addr (string-trim addr)))
</span></span><span style="display:flex;"><span>                          (when (not (string-empty-p clean-addr))
</span></span><span style="display:flex;"><span>                            (<span style="color:#a6e22e">downcase</span>
</span></span><span style="display:flex;"><span>                             (if (<span style="color:#a6e22e">string-match</span> <span style="color:#e6db74">&#34;&lt;\\([^&gt;]+\\)&gt;&#34;</span> clean-addr)
</span></span><span style="display:flex;"><span>                                 (string-trim (match-string <span style="color:#ae81ff">1</span> clean-addr))
</span></span><span style="display:flex;"><span>                               clean-addr)))))
</span></span><span style="display:flex;"><span>                      (split-string recipients <span style="color:#e6db74">&#34;,&#34;</span> <span style="color:#66d9ef">t</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/mail-sign-encrypt ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Auto-encrypt if all recipients have keys, else just sign.&#34;</span>
</span></span><span style="display:flex;"><span>    (let ((trusted-emails (gpg-list-emails-available))
</span></span><span style="display:flex;"><span>          (recipients (thanos/mail-list-recipients-from-buffer)))
</span></span><span style="display:flex;"><span>      (if (cl-every (lambda (r) (<span style="color:#a6e22e">member</span> r trusted-emails)) recipients)
</span></span><span style="display:flex;"><span>          (progn
</span></span><span style="display:flex;"><span>            (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;Encrypting message.&#34;</span>)
</span></span><span style="display:flex;"><span>            (mml-secure-message-sign-encrypt))
</span></span><span style="display:flex;"><span>        (progn
</span></span><span style="display:flex;"><span>          (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;Just signing message.&#34;</span>)
</span></span><span style="display:flex;"><span>          (mml-secure-message-sign)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (add-hook <span style="color:#e6db74">&#39;message-send-hook</span> <span style="color:#a6e22e">#&#39;</span>thanos/mail-sign-encrypt)
</span></span><span style="display:flex;"><span>  :custom
</span></span><span style="display:flex;"><span>  (mml-secure-openpgp-signers <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;62B758D0F6719938BC09CECA339F736C3A720928&#34;</span>))) <span style="color:#75715e">;; Change this to your own key!</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Daily Driving a Raspberry Pi 5</title>
      <link>https://thanosapollo.org/posts/daily-drive-pi5-01/</link>
      <pubDate>Fri, 31 Oct 2025 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/daily-drive-pi5-01/</guid>
      <description>Replacing my x220 laptop with a Raspberry Pi 5.</description>
      <content:encoded><![CDATA[<p>After switching from Apple devices to GNU/Linux, I&rsquo;ve enjoyed numerous
advantages. However, there&rsquo;s always been <em>one</em> thing that used to
make me look back: <em>battery life</em>, or the lack thereof.</p>
<p>Not anymore :)</p>
<p><strong>TLDR</strong>: I switched from a <a href="/images/setup-07-11-2023.jpg">thinkpad x220</a> to
a Raspberry Pi 5, which I use to access my desktop remotely.</p>
<figure>
    <img loading="lazy" src="/images/pi-monitor-back-01.png" width="80%" height="80%"/> 
</figure>

<blockquote>
<p>Raspberry Pi 5 with 3d printed custom VESA mount on Raspberry Pi Monitor</p>
</blockquote>
<h2 id="project-goals">Project Goals</h2>
<p>My aim with this &ldquo;project&rdquo; is to have a small, portable, and modular
device that I can simply toss in my bag and not worry about it&rsquo;s
battery life throughout the day.</p>
<p>The extra thing that I want, is to prove that you do not need to &ldquo;sell
your kidney&rdquo; and bow down to a corporation for the &lsquo;privilege&rsquo; to use
their hardware designed for obsolescence or their bloated software.</p>
<p>Hardware I&rsquo;m using:</p>
<ul>
<li>
<p>Things I&rsquo;ve purchased:</p>
<ul>
<li>Raspberry Pi 5 8GB</li>
<li>Raspberry Pi Monitor</li>
</ul>
</li>
<li>
<p>Things I&rsquo;ve already had:</p>
<ul>
<li>27000 mAh power bank</li>
<li>Keyboard</li>
</ul>
</li>
</ul>
<blockquote>
<p>I bought a Raspberry Pi 5 kit that came with a case fan for 100€.
The total cost for this project was 195€, for the Pi and the monitor.</p>
</blockquote>
<h3 id="battery-life">Battery Life</h3>
<p>I&rsquo;m usually out of home for over 7 hours a day for my studies, and I
enjoy studying in cafes and libraries. I&rsquo;ve missed having a device
with a battery life of 10+ hours, as my x220 barely lasts more than
4.5 hours.</p>
<p>Using a <code>27000mAh</code> power bank, I get ~15 hours of battery life.
I also carry an extra <em>&ldquo;emergency&rdquo;</em> power bank.</p>
<blockquote>
<p>With great power (and battery life) comes great productivity</p>
</blockquote>
<figure>
    <img loading="lazy" src="/images/pi-battery-usage.png" width="30%" height="30%"/> 
</figure>

<blockquote>
<p>The monitor consumes more energy than my Pi.</p>
</blockquote>
<h3 id="modularity">Modularity</h3>
<p>I strongly dislike laptop keyboards and I insist on using ones with a
trackpoint. I&rsquo;m currently using a <a href="https://tex.com.tw/products/shinobi">shinobi
keyboard</a>, which I can simply
plug into my Raspberry Pi and use just like on my desktop.</p>
<p>If I do not like something about my Pi setup, it&rsquo;d be trivial to
change, such using a new monitor, a new keyboard or another power bank.</p>
<h3 id="performance-file-synchronization">Performance &amp; File Synchronization</h3>
<p>Can the Pi outperform a modern laptop of &gt;1000€ price range? Yes and No :)</p>
<p>Now, you might be wondering; how can my Pi deliver better performance
than, say, a MacBook Air? A valid question, but as a GNU+Linux user,
I&rsquo;ve come to embrace the possibilities. Anything&rsquo;s possible with a
bit of hackery and FOSS magic.</p>
<p>I use <a href="https://github.com/neonkore/waypipe">waypipe</a>, a Wayland proxy,
to run Emacs remotely over a network. Emacs runs on my desktop, but I
access it from my Pi, great performance while seamlessly accessing all
my desktop files, such as my notes and PDFs, this also removes any
need for syncing files between devices.</p>
<blockquote>
<p>I have fiber connection, so there isn&rsquo;t any latency issues between
my devices using a wireguard VPN.</p>
</blockquote>
<figure>
    <img loading="lazy" src="/images/pi-waypipe-01.png"/> 
</figure>

<blockquote>
<p>Accessing my desktop Emacs session remotely, opening a PDF and eshell.</p>
</blockquote>
<h2 id="conclusion">Conclusion</h2>
<p>I will be using this setup for the rest of the academic year. I might
record a more detailed video with tips and tricks for others that
want to try something similar.</p>
<p>So far this has been more than an ideal setup for me, since I quite
often forget to sync my notes and projects between devices. Not
having to worry anymore about the battery life of my device is
quite relaxing as well.</p>]]></content:encoded>
    </item>
    <item>
      <title>Emacs Everywhere, even in Wayland</title>
      <link>https://thanosapollo.org/posts/use-emacs-everywhere/</link>
      <pubDate>Sat, 19 Jul 2025 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/use-emacs-everywhere/</guid>
      <description>How to use Emacs for input in any scenario in Wayland</description>
      <content:encoded><![CDATA[<p>If you are anything like me, you probably feel something is wrong
whenever you have to input text outside of Emacs. Fear not,
there&rsquo;s a solution.</p>
<p>Here&rsquo;s a simple code snippet to launch an emacs temp frame for input instead.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun thanos/wtype-text (text)
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Process TEXT for wtype, handling newlines properly.&#34;</span>
</span></span><span style="display:flex;"><span>  (let* ((has-final-newline (string-match-p <span style="color:#e6db74">&#34;\n$&#34;</span> text))
</span></span><span style="display:flex;"><span>         (lines (split-string text <span style="color:#e6db74">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span>         (last-idx (<span style="color:#a6e22e">1-</span> (<span style="color:#a6e22e">length</span> lines))))
</span></span><span style="display:flex;"><span>    (string-join
</span></span><span style="display:flex;"><span>     (cl-loop for line in lines
</span></span><span style="display:flex;"><span>              for i from <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>              collect (cond
</span></span><span style="display:flex;"><span>                       <span style="color:#75715e">;; Last line without final newline</span>
</span></span><span style="display:flex;"><span>                       ((and (<span style="color:#a6e22e">=</span> i last-idx) (not has-final-newline))
</span></span><span style="display:flex;"><span>                        (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;wtype -s 350 \&#34;%s\&#34;&#34;</span>
</span></span><span style="display:flex;"><span>                                (replace-regexp-in-string <span style="color:#e6db74">&#34;\&#34;&#34;</span> <span style="color:#e6db74">&#34;\\\\\&#34;&#34;</span> line)))
</span></span><span style="display:flex;"><span>                       <span style="color:#75715e">;; Any other line</span>
</span></span><span style="display:flex;"><span>                       (<span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>                        (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;wtype -s 350 \&#34;%s\&#34; &amp;&amp; wtype -k Return&#34;</span>
</span></span><span style="display:flex;"><span>                                (replace-regexp-in-string <span style="color:#e6db74">&#34;\&#34;&#34;</span> <span style="color:#e6db74">&#34;\\\\\&#34;&#34;</span> line)))))
</span></span><span style="display:flex;"><span>     <span style="color:#e6db74">&#34; &amp;&amp; &#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(defun thanos/type ()
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Launch a temporary frame with a clean buffer for typing.&#34;</span>
</span></span><span style="display:flex;"><span>  (interactive)
</span></span><span style="display:flex;"><span>  (let ((frame (make-frame <span style="color:#f92672">&#39;</span>((name <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;emacs-float&#34;</span>)
</span></span><span style="display:flex;"><span>                             (fullscreen <span style="color:#f92672">.</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>                             (undecorated <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)
</span></span><span style="display:flex;"><span>                             (width <span style="color:#f92672">.</span> <span style="color:#ae81ff">70</span>)
</span></span><span style="display:flex;"><span>                             (height <span style="color:#f92672">.</span> <span style="color:#ae81ff">20</span>))))
</span></span><span style="display:flex;"><span>        (buf (<span style="color:#a6e22e">get-buffer-create</span> <span style="color:#e6db74">&#34;emacs-float&#34;</span>)))
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">select-frame</span> frame)
</span></span><span style="display:flex;"><span>    (switch-to-buffer buf)
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">erase-buffer</span>)
</span></span><span style="display:flex;"><span>    (org-mode)
</span></span><span style="display:flex;"><span>    (setq-local header-line-format
</span></span><span style="display:flex;"><span>                (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34; %s to insert text or %s to cancel.&#34;</span>
</span></span><span style="display:flex;"><span>                        (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;C-c C-c&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;help-key-binding</span>)
</span></span><span style="display:flex;"><span>            (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;C-c C-k&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;help-key-binding</span>)))
</span></span><span style="display:flex;"><span>    (local-set-key (kbd <span style="color:#e6db74">&#34;C-c C-k&#34;</span>)
</span></span><span style="display:flex;"><span>           (lambda () (interactive)
</span></span><span style="display:flex;"><span>             (kill-new (<span style="color:#a6e22e">buffer-string</span>))
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">delete-frame</span>)))
</span></span><span style="display:flex;"><span>    (local-set-key (kbd <span style="color:#e6db74">&#34;C-c C-c&#34;</span>)
</span></span><span style="display:flex;"><span>           (lambda () (interactive)
</span></span><span style="display:flex;"><span>             (start-process-shell-command
</span></span><span style="display:flex;"><span>              <span style="color:#e6db74">&#34;wtype&#34;</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>              (thanos/wtype-text (<span style="color:#a6e22e">buffer-string</span>)))
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">delete-frame</span>)))))
</span></span></code></pre></div><blockquote>
<p><em>Make sure <code>wtype</code> is installed in your system for the above snippet to work.</em></p>
</blockquote>
<p>All you have to do now is just bind <code>emacsclient --eval '(thanos/type)'</code>
to a shortcut of your liking.</p>
<p>On my Hyprland setup I&rsquo;m using the following settings</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>bind = $mainMod, j, exec, emacsclient --eval &#39;(thanos/type)&#39;
</span></span><span style="display:flex;"><span>windowrulev2 = float,class:^(emacs)$,title:^(emacs-float)$ # Launch as a floating window.
</span></span></code></pre></div><blockquote>
<p>For xorg users, you can simply rely on the <a href="https://github.com/tecosaur/emacs-everywhere">Emacs Everywhere</a>
package. <em>Unfortunately it does not support Wayland yet and I have
not tried it.</em></p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Major update for Gnosis: 0.5.0 release</title>
      <link>https://thanosapollo.org/posts/gnosis-0-5-0-release/</link>
      <pubDate>Tue, 17 Jun 2025 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-0-5-0-release/</guid>
      <description>Gnosis just got a major update with this new release.  With the long promised support of org-mode being added along with other major changes.</description>
      <content:encoded><![CDATA[<p>Gnosis just got a major update with this new release. With the long
promised support of <strong>org-mode</strong> being added along with support for
linking notes to
<a href="https://thanosapollo.org/projects/org-gnosis/">org-gnosis</a> nodes.</p>
<h2 id="org-mode-support">Org Mode Support</h2>
<p>After hacking on org-gnosis and gaining a better
understanding of how org-mode works, I decided to use org-mode for
creating and exporting gnosis notes.</p>
<p>Notes, no matter their note type, will now be as follows:</p>
<blockquote>
<p>Cloze type example.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-org" data-lang="org"><span style="display:flex;"><span>*<span style="font-weight:bold"> Thema                     </span><span style="font-style:italic"> :pharmacology:antimicrobials:penicillin:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:GNOSIS_ID: NEW
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">:GNOSIS_TYPE: cloze
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Keimenon
</span></span><span style="display:flex;"><span>What is the treatment for Actinomyces infection?
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Penicillin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Hypothesis
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>drug type
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Answer
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Penicillin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Parathema
</span></span><span style="display:flex;"><span>Sulfonamides → Nocardia
</span></span><span style="display:flex;"><span>Actinomyces → [[<span style="color:#a6e22e">id:680ca944-8ee9-4513-92d6-25696ee01f48</span>][<span style="color:#f92672">Penicillin</span>]]
</span></span><span style="display:flex;"><span>(treatment is a SNAP)
</span></span></code></pre></div><blockquote>
<p>Note that anki-like syntax is still supported for clozes.</p>
</blockquote>
<!--quoteend-->
<blockquote>
<p>MCQ example</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-org" data-lang="org"><span style="display:flex;"><span>*<span style="font-weight:bold"> Thema                                                           </span><span style="font-style:italic"> :clinical:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:GNOSIS_ID: NEW
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">:GNOSIS_TYPE: mcq
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Keimenon
</span></span><span style="display:flex;"><span>A 60-year-old man comes to the physician with chills, nausea, and
</span></span><span style="display:flex;"><span>diffuse muscle aches for 3 days. His niece had similar symptoms 2
</span></span><span style="display:flex;"><span>weeks ago and H3N2 influenza strain was isolated from her respiratory
</span></span><span style="display:flex;"><span>secretions. He received his influenza vaccination 2 months ago. His
</span></span><span style="display:flex;"><span>temperature is 38.5°C. A rapid influenza test is
</span></span><span style="display:flex;"><span>positive. Which of the following mechanisms best explains this
</span></span><span style="display:flex;"><span>patient&#39;s infection despite vaccination?
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Hypothesis
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Random point mutations within viral genome
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Complementing with functional viral proteins
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Exchange of viral genes between chromosomes
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Reassortment of viral RNA segments
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Acquisition of viral surface proteins
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Answer
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Random point mutations within viral genome
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Parathema
</span></span><span style="display:flex;"><span>Random point mutations within the viral genome are responsible for
</span></span><span style="display:flex;"><span>antigenic drift, which creates a new virus strain.
</span></span></code></pre></div><p>Each note is a <strong>thema</strong> consisting of the following components:</p>
<ul>
<li><strong>Keimenon</strong>; The main text or question.</li>
<li><strong>Hypothesis</strong>; Assumptions/hints for the text to guide to the right answer
<ul>
<li>For example this is used as hints for cloze type or as choices in MCQs</li>
</ul>
</li>
<li><strong>Answer</strong>; The correct response or solution to the keimenon.</li>
<li><strong>Parathema</strong>; expansion of keimenon, that can include links to e.g
org-gnosis topics or even files, serving as a way to link org-gnosis
topics to current thema.</li>
</ul>
<p>Optionally, you can use also add tags for each note.</p>
<p>Notes/themas can have multiple hypotheses and answers (<em>depending on
their type</em>), separated by <code>gnosis-export-separator</code>, which defaults to
<code>&quot;\n-&quot;</code> (a new line followed by a dash).</p>
<h2 id="support-for-exporting-decks">Support for exporting decks</h2>
<p>Support for exporting decks as org files via <code>gnosis-export-deck</code> has
been added.</p>
<h2 id="support-for-org-gnosis-notes">Support for org-gnosis notes</h2>
<blockquote>
<p>With this update org-gnosis is finally part of gnosis. The goal is
not to just have a spaced repetition tool, but an all-in-one
learning tool.</p>
</blockquote>
<p>With this new update you can do reviews for specific <strong>org-gnosis</strong>
topics.</p>
<ul>
<li>Use <code>M-x gnosis-review-topic</code> to select a topic from your org-gnosis
notes to review all linked themas.</li>
<li>You can link a thema to an org-gnosis topic by adding an org id
link to either the parathema <em>(recommended)</em> or keimenon, using
<code>M-x org-gnosis-insert</code>.</li>
</ul>
<blockquote>
<p>Future versions will further expand on this functionality.</p>
</blockquote>
<h2 id="deprecated-support-for-images">Deprecated support for images</h2>
<ul>
<li>Image support will be rewritten in the next minor version
<ul>
<li>Support to display file links of images will be added.</li>
</ul>
</li>
</ul>
<h2 id="deprecated-support-for-y-or-n-notes">Deprecated support for y-or-n notes</h2>
<p>With this update your current <code>y-or-n</code> notes will be converted into MCQ
type, with &ldquo;Yes&rdquo; &amp; &ldquo;No&rdquo; choices.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Emacs Note Taking &amp; Journaling using org-gnosis [Video]</title>
      <link>https://thanosapollo.org/posts/org-gnosis-overview/</link>
      <pubDate>Mon, 03 Mar 2025 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-overview/</guid>
      <description>Video overview about org-gnosis</description>
      <content:encoded><![CDATA[<center><i>Emacs Note Taking & Journaling with org-gnosis</i>
<iframe width="560" height="315" src="https://www.youtube.com/embed/5SkLa7jGjl0?si=ayncyQBxQ19NYqgV" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<h2 id="video-notes">Video notes</h2>
<h3 id="org-gnosis-overview">Org Gnosis Overview</h3>
<ul>
<li>
<p><strong>Org Gnosis</strong> <em>Organization of Gnosis (Knowledge)</em></p>
</li>
<li>
<p>Org Gnosis a a minimal org-mode parsing tool that organizes the data
of your notes as atomic nodes in an sqlite database.</p>
<ul>
<li>Org Gnosis provides a roam-like workflow, akin to Roam Research,
Logseq and org-roam, with support for journaling.</li>
</ul>
</li>
<li>
<p>In org-gnosis there are 2 types of nodes, gnosis nodes &amp; journal nodes.</p>
</li>
</ul>
<h3 id="installation-configuration">Installation &amp; Configuration</h3>
<ul>
<li><em>Refer to the project&rsquo;s
<a href="https://thanosapollo.org/projects/org-gnosis/">website</a> for the
latest installation instructions.</em></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package org-gnosis
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  :init
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/notes-map</span>)
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/journal-map</span>)
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; I put my databse inside org-gnosis-dir to keep it in sync</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; between machines, using git.</span>
</span></span><span style="display:flex;"><span>  (setf org-gnosis-db (emacsql-sqlite-open
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">&#34;data.db&#34;</span> org-gnosis-dir)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (setf org-gnosis-dir <span style="color:#e6db74">&#34;~/Notes&#34;</span>
</span></span><span style="display:flex;"><span>  org-gnosis-node-templates
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;Default&#34;</span> (lambda () <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#e6db74">&#34;#+startup: content\n&#34;</span>)))
</span></span><span style="display:flex;"><span>  org-gnosis-journal-templates
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;2050 Plan&#34;</span> journal/plan-2050)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;Empty&#34;</span> (lambda () <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#e6db74">&#34;#+startup: content\n&#34;</span>)))
</span></span><span style="display:flex;"><span>  org-gnosis-show-tags <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  org-gnosis-create-as-gpg <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  org-gnosis-completing-read-func <span style="color:#a6e22e">#&#39;</span>org-completing-read)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun journal/plan-2050 ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;My journaling template for 2050-01-01.&#34;</span>
</span></span><span style="display:flex;"><span>    (let ((days-remaining (<span style="color:#a6e22e">-</span> (time-to-days (<span style="color:#a6e22e">encode-time</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2050</span>))
</span></span><span style="display:flex;"><span>               (time-to-days (<span style="color:#a6e22e">current-time</span>)))))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">format</span>
</span></span><span style="display:flex;"><span>       <span style="color:#e6db74">&#34;\nDays until 2050: *%s* \n\n* Records\n\n* Daily notes\n* Goals\n%s&#34;</span>
</span></span><span style="display:flex;"><span>       days-remaining (org-gnosis-todos))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c n&#34;</span> <span style="color:#f92672">.</span> thanos/notes-map)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c j&#34;</span> <span style="color:#f92672">.</span> thanos/journal-map)
</span></span><span style="display:flex;"><span>   :map thanos/notes-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-find)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-insert)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;t&#34;</span> <span style="color:#f92672">.</span> org-gnosis-find-by-tag)
</span></span><span style="display:flex;"><span>   :map thanos/journal-map
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;j&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-find)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-insert)
</span></span><span style="display:flex;"><span>   :map org-gnosis-mode-map
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c C-.&#34;</span> <span style="color:#f92672">.</span> org-gnosis-insert-tags)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c i&#34;</span> <span style="color:#f92672">.</span> org-id-get-create)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c C-o&#34;</span> <span style="color:#f92672">.</span> thanos/org-open-at-point)))
</span></span></code></pre></div><h4 id="epa-easypgp-assistant">EPA (EasyPGP Assistant)</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package epa
</span></span><span style="display:flex;"><span>  :defer <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf epa-keys-select-method <span style="color:#e6db74">&#39;minibuffer</span>
</span></span><span style="display:flex;"><span>  epa-file-encrypt-to <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;your-pgp-key&#34;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Do not prompt for key selection, we are only using the above key.</span>
</span></span><span style="display:flex;"><span>  epa-file-select-keys <span style="color:#e6db74">&#39;silent</span>))
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Emacs As Your Terminal Emulator [Video]</title>
      <link>https://thanosapollo.org/posts/emacs-shells-video/</link>
      <pubDate>Sat, 25 Jan 2025 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-shells-video/</guid>
      <description>Short video about Emacs shell interactions</description>
      <content:encoded><![CDATA[<center><i>Emacs As Your Terminal Emulator</i>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Qo7WQjbE2io?si=PAWUzeVw79DfBA4s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<h3 id="emacs-as-your-terminal-emulator-video">Emacs As Your Terminal Emulator [Video]</h3>
<ul>
<li>Emacs offers an enhanced experience for interacting with shell tools
&amp; <em>may</em> be the most extensible terminal emulator available.</li>
<li>Provides seamless integration between shell tools &amp; editing
capabilities.</li>
</ul>
<h2 id="using-shell-commands-from-within-a-buffer">Using shell commands from within a buffer</h2>
<h3 id="shell-command">shell-command</h3>
<ul>
<li><code>M-! CMD &lt;RET&gt;</code></li>
<li>Run the shell command CMD and display the output.</li>
</ul>
<h3 id="async-shell-command">async-shell-command</h3>
<ul>
<li><code>M-&amp; CMD &lt;RET&gt;</code></li>
<li>Run the shell command CMD asynchronously, and display the output</li>
</ul>
<h3 id="shell-command-on-region">shell-command-on-region</h3>
<ul>
<li><code>M-| CMD &lt;RET&gt;</code></li>
<li>Run the shell command CMD with region contents as input; optionally
replace the region with the output</li>
</ul>
<h2 id="emacs-as-a-terminal-emulator">Emacs as a Terminal Emulator</h2>
<h3 id="shell">Shell</h3>
<ul>
<li><code>M-x shell</code></li>
<li>A subshell with input and output through an Emacs
buffer. You can then give commands interactively.</li>
</ul>
<h4 id="my-configuration">My configuration</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package shell
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (defun thanos/shell (n)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Create or switch to a shell buffer.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive <span style="color:#e6db74">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span>    (let* ((num (if n (<span style="color:#a6e22e">prefix-numeric-value</span> n) <span style="color:#66d9ef">nil</span>))
</span></span><span style="display:flex;"><span>           (buf-name (if num (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;*shell&lt;%d&gt;*&#34;</span> num) <span style="color:#e6db74">&#34;*shell*&#34;</span>)))
</span></span><span style="display:flex;"><span>      (shell buf-name)))
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c v&#34;</span> <span style="color:#f92672">.</span> thanos/shell)
</span></span><span style="display:flex;"><span>         :map shell-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;C-l&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;comint-clear-buffer</span>))
</span></span><span style="display:flex;"><span>  :hook ((shell-mode <span style="color:#f92672">.</span> (lambda () (display-line-numbers-mode <span style="color:#ae81ff">-1</span>)))))
</span></span></code></pre></div><h3 id="eshell">Eshell</h3>
<ul>
<li><code>M-x eshell</code></li>
<li>Shell implemented entirely in Emacs Lisp</li>
</ul>
<h4 id="my-configuration-1">My configuration</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package eshell
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Prompt</span>
</span></span><span style="display:flex;"><span>  (defun eshell-git-info ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Return a string with git info.&#34;</span>
</span></span><span style="display:flex;"><span>    (when (<span style="color:#a6e22e">eq</span> (<span style="color:#a6e22e">call-process</span> <span style="color:#e6db74">&#34;git&#34;</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">&#34;rev-parse&#34;</span> <span style="color:#e6db74">&#34;--is-inside-work-tree&#34;</span>) <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>      (let* ((branch-raw (shell-command-to-string <span style="color:#e6db74">&#34;git rev-parse --abbrev-ref HEAD&#34;</span>))
</span></span><span style="display:flex;"><span>             (branch (if (or (string-match-p <span style="color:#e6db74">&#34;^fatal&#34;</span> branch-raw)
</span></span><span style="display:flex;"><span>                             (string-match-p <span style="color:#e6db74">&#34;^error&#34;</span> branch-raw))
</span></span><span style="display:flex;"><span>                         <span style="color:#e6db74">&#34;Unknown&#34;</span>
</span></span><span style="display:flex;"><span>                       (string-trim branch-raw)))
</span></span><span style="display:flex;"><span>             (dirty (not
</span></span><span style="display:flex;"><span>                     (string= <span style="color:#e6db74">&#34;&#34;</span> (string-trim (shell-command-to-string <span style="color:#e6db74">&#34;git status --porcelain&#34;</span>)))))
</span></span><span style="display:flex;"><span>             (dirty-info (if dirty <span style="color:#e6db74">&#34; ✎&#34;</span> <span style="color:#e6db74">&#34; ✔&#34;</span>)))
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">concat</span> (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;⎇ &#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-green-warmer</span>)
</span></span><span style="display:flex;"><span>                (<span style="color:#a6e22e">propertize</span> branch <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-magenta-warmer</span>)
</span></span><span style="display:flex;"><span>                (<span style="color:#a6e22e">propertize</span> dirty-info <span style="color:#e6db74">&#39;face</span>
</span></span><span style="display:flex;"><span>                            (if dirty <span style="color:#e6db74">&#39;modus-themes-fg-red</span> <span style="color:#e6db74">&#39;modus-themes-fg-green</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun eshell-prompt-multiline ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Eshell Multiline Git prompt.&#34;</span>
</span></span><span style="display:flex;"><span>    (let ((separator (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34; | &#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;font-lock-comment-face</span>))
</span></span><span style="display:flex;"><span>          (hr (<span style="color:#a6e22e">propertize</span> (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;\n&#34;</span> (<span style="color:#a6e22e">make-string</span> (<span style="color:#a6e22e">/</span> (<span style="color:#a6e22e">window-total-width</span>) <span style="color:#ae81ff">2</span>) <span style="color:#e6db74">?─</span>) <span style="color:#e6db74">&#34;\n&#34;</span>) <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;font-lock-comment-face</span>))
</span></span><span style="display:flex;"><span>          (dir (<span style="color:#a6e22e">propertize</span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;%s&#34;</span> (abbreviate-file-name (eshell/pwd))) <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-yellow-warmer</span>))
</span></span><span style="display:flex;"><span>          (git-info (eshell-git-info))
</span></span><span style="display:flex;"><span>          (time (<span style="color:#a6e22e">propertize</span> (<span style="color:#a6e22e">format-time-string</span> <span style="color:#e6db74">&#34;%H:%M:%S&#34;</span>) <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;font-lock-comment-face</span>))
</span></span><span style="display:flex;"><span>          (sign (if (<span style="color:#a6e22e">=</span> (<span style="color:#a6e22e">user-uid</span>) <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>                    (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;\n#&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-blue-intense</span>)
</span></span><span style="display:flex;"><span>                  (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;\nλ&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-red-warmer</span>))))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">concat</span> hr dir separator git-info separator time sign <span style="color:#e6db74">&#34; &#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (setf eshell-prompt-function <span style="color:#e6db74">&#39;eshell-prompt-multiline</span>
</span></span><span style="display:flex;"><span>        eshell-highlight-prompt <span style="color:#66d9ef">nil</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Aliases</span>
</span></span><span style="display:flex;"><span>  (defun eshell/o (file)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Open FILE.&#34;</span>
</span></span><span style="display:flex;"><span>    (find-file file))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defvar thanos/aliases
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#39;</span>((ll <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;ls -lah&#34;</span>)
</span></span><span style="display:flex;"><span>      (clear <span style="color:#f92672">.</span> clear-scrollback)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/set-eshell-aliases (aliases)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Set ALIASES as eshell aliases.&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">;; Remove aliases file</span>
</span></span><span style="display:flex;"><span>    (when (and eshell-aliases-file
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">file-exists-p</span> eshell-aliases-file))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">delete-file</span> eshell-aliases-file))
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">mapc</span> (lambda (alias)
</span></span><span style="display:flex;"><span>            (let ((name (<span style="color:#a6e22e">symbol-name</span> (<span style="color:#a6e22e">car</span> alias)))
</span></span><span style="display:flex;"><span>                  (command (<span style="color:#a6e22e">cdr</span> alias)))
</span></span><span style="display:flex;"><span>              (eshell/alias name
</span></span><span style="display:flex;"><span>                            (cond
</span></span><span style="display:flex;"><span>                             ((<span style="color:#a6e22e">stringp</span> command) command)
</span></span><span style="display:flex;"><span>                             ((<span style="color:#a6e22e">symbolp</span> command) (<span style="color:#a6e22e">symbol-name</span> command))
</span></span><span style="display:flex;"><span>                             (<span style="color:#66d9ef">t</span> (<span style="color:#a6e22e">error</span> <span style="color:#e6db74">&#34;Unsupported alias command type&#34;</span>))))))
</span></span><span style="display:flex;"><span>          aliases))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Rebinds</span>
</span></span><span style="display:flex;"><span>  (defun thanos/eshell-clear ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Interactive call for clear-scrollback.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (eshell/clear-scrollback))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/eshell-preview-insert ()
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (completion-preview-insert)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">;; This funciton just deletes the extra space inserted after</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">;; completion.</span>
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">delete-char</span> <span style="color:#ae81ff">-1</span>))
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c e&#34;</span> <span style="color:#f92672">.</span> eshell)
</span></span><span style="display:flex;"><span>         :map eshell-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;C-l&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;thanos/eshell-clear</span>)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;&lt;tab&gt;&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;thanos/eshell-preview-insert</span>)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;C-M-i&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;completion-at-point</span>))
</span></span><span style="display:flex;"><span>  :hook ((eshell-mode <span style="color:#f92672">.</span> (lambda ()
</span></span><span style="display:flex;"><span>                          (thanos/set-eshell-aliases thanos/aliases)
</span></span><span style="display:flex;"><span>                          (display-line-numbers-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>                          (eshell-cmpl-mode <span style="color:#ae81ff">-1</span>)))))
</span></span></code></pre></div><h3 id="eat">Eat</h3>
<p><em><a href="https://codeberg.org/akib/emacs-eat">Emulate a terminal (Eat)</a></em></p>
<ul>
<li>xterm-like emulator, written in Emacs Lisp.</li>
<li>Although it&rsquo;s a standalone terminal for Emacs, similar to <code>term</code>,
I&rsquo;ve mostly used this package to enhance <code>eshell</code>.</li>
</ul>
<h4 id="my-configuration-2">My configuration</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package eat
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf eshell-visual-commands <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>        eat-term-name <span style="color:#e6db74">&#34;xterm-256color&#34;</span>)
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c V&#34;</span> <span style="color:#f92672">.</span> eat))
</span></span><span style="display:flex;"><span>  :hook ((eshell-mode <span style="color:#f92672">.</span> eat-eshell-mode)
</span></span><span style="display:flex;"><span>         (eshell-mode <span style="color:#f92672">.</span> eat-eshell-visual-command-mode)
</span></span><span style="display:flex;"><span>         (eat-mode <span style="color:#f92672">.</span> (lambda () (visual-line-mode <span style="color:#ae81ff">-1</span>)))))
</span></span></code></pre></div><h3 id="term-ansi-term">Term &amp; Ansi-Term</h3>
<ul>
<li><code>M-x term</code> | <code>M-x ansi-term</code>
<ul>
<li><strong>ansi-term</strong> is the same as term, except that it always creates a
new buffer and <code>C-x</code> is being marked as an escape-char.</li>
</ul>
</li>
<li>Runs a subshell with input and output through an Emacs buffer.</li>
</ul>
<h4 id="how-to-use">How to use</h4>
<ul>
<li>While in <code>term-mode</code> <code>C-c CHAR</code> is equivalent to <code>C-x CHAR</code>.
<ul>
<li>Example <code>C-c o</code> is the global binding <code>C-x o</code> <em>other-window</em></li>
</ul>
</li>
<li><code>C-c C-j</code> switches to <code>term-line-mode</code> <em>which allows navigation similar to shell</em></li>
<li><code>C-c C-k</code> switches back to <code>term-char-mode</code></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Progress update on org-gnosis &amp; a graphical interface addition.</title>
      <link>https://thanosapollo.org/posts/org-gnosis-progress-1/</link>
      <pubDate>Wed, 18 Dec 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-progress-1/</guid>
      <description>Progress update on org-gnosis, a roam-like note taking system.</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve been working on a &ldquo;roam-like&rdquo; note taking system, to replace &amp;
update my current <code>org-roam</code> workflow. This post is a minor update on
the current state of it&rsquo;s development.</p>
<blockquote>
<p>org-gnosis node &amp; my <a href="https://git.thanosapollo.org/org-roam-ui/">fork</a> of org-roam-ui</p>
</blockquote>
<p><strong>Project Name</strong>: <code>org-gnosis</code> | <strong>Org*anization of *Gnosis</strong></p>
<h2 id="goals">Goals</h2>
<p>The goals of <code>org-gnosis</code> are as follows:</p>
<ul>
<li>Keep it minimal, only implement parsing &amp; input data to a database.
<ul>
<li>Do not want to exceed 700 lines of code, <em>currently it&rsquo;s at 490</em>.</li>
</ul>
</li>
<li>Incorporate nodes as sources for <a href="/projects/gnosis/">gnosis</a> notes.
<ul>
<li>Having nodes as sources can replace my <em>extras</em> section.</li>
</ul>
</li>
<li>Make it easily extensible
<ul>
<li>Parsing functionality of <code>org-gnosis</code> should be easily customized to
work with other note taking tools.</li>
</ul>
</li>
<li>Separate journals from note taking</li>
</ul>
<h2 id="how-things-are-going">How things are going</h2>
<p>The goals above have been achieved, except for the incorporation with
my SRS system &amp; it&rsquo;s customization to parse non <code>org-mode</code> buffers can
be kinda tricky. Despite that, it has been a drop-in replacement for
my previous <code>org-roam</code> workflow.</p>
<p>I&rsquo;ve also created a fork of
<a href="https://git.thanosapollo.org/org-roam-ui/">org-roam-ui</a> that I&rsquo;ve
been using to visualize my notes. I will be testing this package and
<em>hopefully</em> publishing on either nongnu elpa or melpa <em>soon</em>.</p>
<p>If you are interested, try it out from this repo
<a href="https://git.thanosapollo.org/org-gnosis/">here</a>. If you find any
issues or got any questions feel free to email me.</p>]]></content:encoded>
    </item>
    <item>
      <title>Emacs 30 Built-in Completion UI &amp; Styles [Video]</title>
      <link>https://thanosapollo.org/posts/emacs-built-in-completions-video/</link>
      <pubDate>Thu, 12 Dec 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-built-in-completions-video/</guid>
      <description>Short video about Emacs 30 Built-in Completion UI &amp;amp; Styles</description>
      <content:encoded><![CDATA[<center>
<p><i>Emacs 30 Built-in Completion UI & Styles</i><p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/-ZeoGVtMLaU?si=nvEEv_8RPVa2EUij" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<h2 id="video-notes">Video notes:</h2>
<ul>
<li>When referring to &ldquo;Emacs Completions&rdquo;, I refer to Completion Styles &amp; UI</li>
<li>I&rsquo;ve often relied on third-party packages to emulate features from
other text editors. For instance, I&rsquo;ve long used <code>vertico</code>,
<code>corfu</code> and <code>orderless</code>.
<ul>
<li>While I still recommend these packages, I became curious about
using Emacs without depending on third-party options.</li>
<li>My current setup tries to emulate my workflow with the packages
mentioned above.</li>
</ul>
</li>
<li>The catalyst that pushed me to try the built-in completion is the
addition of <code>completion-preview-mode</code> in Emacs 30.</li>
</ul>
<h3 id="mini-buffer-completions">Mini-buffer completions</h3>
<ul>
<li>Emacs does not enable &ldquo;vertical&rdquo; completions for the mini-buffer by
default, but you can enable <code>fido-vertical-mode</code> which comes
built-in with Emacs.
<ul>
<li><code>fido-mode</code> is an enhanced <code>icomplete-mode</code> that emulates
<code>ido-mode</code>, also referred to as <code>fake ido-mode</code>.</li>
</ul>
</li>
</ul>
<h3 id="completion-styles">Completion Styles</h3>
<ul>
<li>Changing <code>completion-styles</code> example:</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf completion-styles <span style="color:#f92672">&#39;</span>(basic flex))
</span></span></code></pre></div><ul>
<li>There is a plethora of completion styles, builtin styles include
<code>flex</code>, which provides &ldquo;fuzzy&rdquo; completions.</li>
</ul>
<h3 id="completion-ui-code-completions">Completion UI &amp; Code completions</h3>
<ul>
<li>Emacs built-in completions have a distinctive approach.</li>
<li>Instead of displaying a popup at point, a new <strong>Completions</strong> buffer
appears when invoking <code>completion-at-point</code>.</li>
</ul>
<p>Example configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf completion-styles <span style="color:#f92672">&#39;</span>(basic flex)
</span></span><span style="display:flex;"><span>      completion-auto-select <span style="color:#66d9ef">t</span> <span style="color:#75715e">;; Show completion on first call</span>
</span></span><span style="display:flex;"><span>      completion-auto-help <span style="color:#e6db74">&#39;visible</span> <span style="color:#75715e">;; Display *Completions* upon first request</span>
</span></span><span style="display:flex;"><span>      completions-format <span style="color:#e6db74">&#39;one-column</span> <span style="color:#75715e">;; Use only one column</span>
</span></span><span style="display:flex;"><span>      completions-sort <span style="color:#e6db74">&#39;historical</span> <span style="color:#75715e">;; Order based on minibuffer history</span>
</span></span><span style="display:flex;"><span>      completions-max-height <span style="color:#ae81ff">20</span> <span style="color:#75715e">;; Limit completions to 15 (completions start at line 5)</span>
</span></span><span style="display:flex;"><span>      completion-ignore-case <span style="color:#66d9ef">t</span>)
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Installing GNU Guix | Using non-free drivers (NonGuix) [Video]</title>
      <link>https://thanosapollo.org/posts/installing-gnu-guix-video/</link>
      <pubDate>Wed, 04 Dec 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/installing-gnu-guix-video/</guid>
      <description>Video tutorial installing GNU Guix, using NonGuix.</description>
      <content:encoded><![CDATA[<center>
<p><i>Installing GNU Guix | Using non-free kernel drivers (Nonguix)</i></p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/p1w8dwHxFnk?si=EA976WIQ-ZFXSUNu" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<h2 id="notes-shown-in-the-video">Notes shown in the video:</h2>
<ul>
<li><strong>GNU Guix</strong> is a GNU distribution</li>
<li>Provides an <strong>emacs-like</strong> operating system, using guile scheme as
it&rsquo;s configuration language.</li>
<li>Only free software is available OOB, uses <code>linux-libre</code> kernel by
default.
<ul>
<li>But since it&rsquo;s an emacs-like OS, we can configure it however
we like, including to use the full linux kernel.</li>
</ul>
</li>
</ul>
<h3 id="installing-guix-using-nonguix">Installing Guix, using <a href="https://gitlab.com/nonguix/nonguix">NonGuix</a></h3>
<ul>
<li><a href="https://gitlab.com/nonguix/nonguix">NonGuix</a> is a Guix channel
that provides non-free software, such as
non-free drivers &amp; games.</li>
<li>NonGuix also provides an iso image that comes with the full linux
kernel</li>
</ul>
<h3 id="download-nonguix-iso">Download nonguix iso</h3>
<ul>
<li>Visit <a href="https://gitlab.com/nonguix/nonguix/-/releases">nonguix releases</a> page</li>
<li>Download the iso image &amp; write it to a USB stick</li>
</ul>
<p><em>Example <code>dd</code> command to use:</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ sudo dd <span style="color:#66d9ef">if</span><span style="color:#f92672">=</span>/path/to/image.iso of<span style="color:#f92672">=</span>/dev/sdX bs<span style="color:#f92672">=</span>4M status<span style="color:#f92672">=</span>progress
</span></span></code></pre></div><h3 id="clone-nonguix-repo">Clone nonguix repo</h3>
<ul>
<li><em>After completing the graphical installer</em></li>
<li>Clone the nonguix repo from <code>https://gitlab.com/nonguix/nonguix</code></li>
<li>Copy the README instructions for channels into
<code>/mnt/etc/channels.scm</code></li>
<li>Add the NonGuix modules to your system configuration and use the
<code>linux-lts</code> kernel on <code>/mnt/etc/config.scm</code></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span><span style="color:#75715e">;; Import nonfree linux module.</span>
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">nongnu</span> packages linux)
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">nongnu</span> system linux-initrd))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">operating-system</span>
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">kernel</span> linux-lts)
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">initrd</span> microcode-initrd)
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">firmware</span> (list linux-firmware))
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>  )
</span></span></code></pre></div><h3 id="install-your-system">Install Your System</h3>
<ul>
<li>Run the following command to install your system:</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ guix time-machine -C /mnt/etc/channels.scm -- system init /mnt/etc/config.scm /mnt
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>org-gnosis | Roam-like note taking system</title>
      <link>https://thanosapollo.org/posts/org-gnosis-01/</link>
      <pubDate>Thu, 21 Nov 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-01/</guid>
      <description>Creating an org-roam replacement</description>
      <content:encoded><![CDATA[<p><code>org-roam</code> was my preferred tool for note taking &amp; journaling, but since
it&rsquo;s author seems to have stepped down &amp; it&rsquo;s implementation is quite
different from how I&rsquo;d approach making a zettelkasten for Emacs, I
decided to start working on a new package, named <code>org-gnosis</code>.</p>
<h2 id="goals-of-this-project">Goals of this project</h2>
<p>The primary objective is to achieve full compatibility with existing
org-roam notes while resolving current database implementation
issues. These goals were met successfully on the first day of
development.</p>
<p>Given that I plan to use this system for the next several years,
performance with large datasets is crucial. I have conducted tests on
org-gnosis with a dataset comprising 70,000 nodes, and it has
demonstrated flawless performance without any issues. Although, the
initialization can take sometime.</p>
<p>Beyond just performance, I want to keep it small and simple,
especially in terms of lines of code. The less lines of code I have
to maintain the happier I am :)</p>
<h2 id="how-to-install">How to install</h2>
<p>This project is <em>only 26 hours</em> old as of now, I have not published it on
any ELPA, but you can find it on this <a href="https://git.thanosapollo.org/org-gnosis/">git
repo</a>, feel free to clone it
and try it out.</p>
<p>Example <code>use-package</code> snippet</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package org-gnosis
</span></span><span style="display:flex;"><span>  :load-path <span style="color:#e6db74">&#34;~/Dev/emacs-lisp/org-gnosis&#34;</span>
</span></span><span style="display:flex;"><span>  :init
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/notes-map</span>)
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/journal-map</span>)
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf org-gnosis-dir <span style="color:#e6db74">&#34;~/Notes&#34;</span>
</span></span><span style="display:flex;"><span>    org-gnosis-show-tags <span style="color:#66d9ef">t</span>) <span style="color:#75715e">;; Enable this if you use a completion system like vertico</span>
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c n&#34;</span> <span style="color:#f92672">.</span> thanos/notes-map)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;C-c j&#34;</span> <span style="color:#f92672">.</span> thanos/journal-map) <span style="color:#75715e">;; You can use &#34;C-c n j&#34; if you prefer</span>
</span></span><span style="display:flex;"><span>     :map thanos/notes-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-find)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-insert)
</span></span><span style="display:flex;"><span>     :map thanos/journal-map
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;j&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-find)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-insert)
</span></span><span style="display:flex;"><span>     :map org-mode-map
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;C-c i&#34;</span> <span style="color:#f92672">.</span> org-id-get-create)))
</span></span></code></pre></div><p>After installing <code>org-gnosis</code> run <code>M-x org-gnosis-db-sync</code> to sync
your database, afterwards just use <code>org-gnosis-find</code> similarly to how
you&rsquo;d use <code>org-roam-find-node</code>.</p>
<blockquote>
<p>This package is still under development, if you encounter any bugs
feel free to email me.</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>RSS Mastery with RSS-Bridge &amp; Elfeed [Video]</title>
      <link>https://thanosapollo.org/posts/rss-video/</link>
      <pubDate>Sat, 09 Nov 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/rss-video/</guid>
      <description>Short video about RSS, RSS-Bridge &amp;amp; Elfeed</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve just published a short video covering the basics of RSS,
RSS-Bridge &amp; Elfeed, it&rsquo;s currently available on
<a href="https://www.youtube.com/watch?v=XvgChZdTvYU">YouTube</a>.</p>
<h2 id="video-notes">Video notes</h2>
<h3 id="what-is-rss">What is RSS?</h3>
<ul>
<li>XML-based web feed that allows users to access updates of
websites, without &ldquo;visiting&rdquo; the website.</li>
<li>Hacktivist including <a href="https://en.wikipedia.org/wiki/Aaron_Swartz">Aaron
Swartz</a> contributed to
the development of RSS</li>
</ul>
<h3 id="why-use-it">Why use it?</h3>
<ul>
<li>Having total control over information you consume
<ul>
<li>Filter/Prioritize content from various sources</li>
<li>Bypass algorithms</li>
<li>Ad-free reading</li>
</ul>
</li>
<li>Offline Access</li>
<li>Time saving</li>
<li>Allows creation of a <strong>personalized</strong> &amp; <strong>decentralized</strong> information hub</li>
</ul>
<h3 id="emacs-rss-elfeed">(+ Emacs RSS) ;; =&gt; &rsquo;elfeed</h3>
<p><strong>No matter what RSS reader you choose, they all get the same job done</strong></p>
<ul>
<li><a href="https://github.com/skeeto/elfeed">Elfeed</a> is a simple &amp; highly customizable RSS client for Emacs
<ul>
<li>Developed by Christopher Wellons (<a href="https://github.com/skeeto">skeeto</a>)</li>
</ul>
</li>
<li>It has a well designed database &amp; tagging system</li>
</ul>
<p><code>use-package</code> installation example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package elfeed
</span></span><span style="display:flex;"><span>  :vc (:url <span style="color:#e6db74">&#34;https://github.com/skeeto/elfeed&#34;</span>) <span style="color:#75715e">;; vc option is available on Emacs 30</span>
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf elfeed-search-filter <span style="color:#e6db74">&#34;@1-week-ago +unread&#34;</span>
</span></span><span style="display:flex;"><span>        browse-url-browser-function <span style="color:#a6e22e">#&#39;</span>browse-url-default-browser
</span></span><span style="display:flex;"><span>        elfeed-db-directory (locate-user-emacs-file <span style="color:#e6db74">&#34;elfeed-db&#34;</span>))
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Feeds Example</span>
</span></span><span style="display:flex;"><span>  (setf elfeed-feeds
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;https://hackaday.com/blog/feed/&#34;</span>
</span></span><span style="display:flex;"><span>           hackaday linux)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Play videos from elfeed</span>
</span></span><span style="display:flex;"><span>  (defun elfeed-mpv (<span style="color:#66d9ef">&amp;optional</span> use-generic-p)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Play video link with mpv.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive <span style="color:#e6db74">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span>    (let ((entries (elfeed-search-selected)))
</span></span><span style="display:flex;"><span>      (cl-loop for entry in entries
</span></span><span style="display:flex;"><span>               do (elfeed-untag entry <span style="color:#e6db74">&#39;unread</span>)
</span></span><span style="display:flex;"><span>               when (elfeed-entry-link entry)
</span></span><span style="display:flex;"><span>               do (start-process-shell-command <span style="color:#e6db74">&#34;elfeed-video&#34;</span> <span style="color:#66d9ef">nil</span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;mpv \&#34;%s\&#34;&#34;</span> it)))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">mapc</span> <span style="color:#a6e22e">#&#39;</span>elfeed-search-update-entry entries)
</span></span><span style="display:flex;"><span>      (unless (use-region-p) (<span style="color:#a6e22e">forward-line</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-x f&#34;</span> <span style="color:#f92672">.</span> elfeed)
</span></span><span style="display:flex;"><span>         :map elfeed-search-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;v&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;elfeed-mpv</span>)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;U&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;elfeed-update</span>)))
</span></span></code></pre></div><h3 id="what-to-do-with-websites-that-do-not-provide-an-rss-feed">What to do with websites that do not provide an RSS feed?</h3>
<ul>
<li>Utilize <a href="https://github.com/RSS-Bridge/rss-bridge">rss-bridge</a> to generate one.</li>
<li>RSS Bridge is easy to self host using docker</li>
</ul>
<p>Example <code>guix</code> service:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(service oci-container-service-type
</span></span><span style="display:flex;"><span>         (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>          (oci-container-configuration
</span></span><span style="display:flex;"><span>           (image <span style="color:#e6db74">&#34;rssbridge/rss-bridge&#34;</span>)
</span></span><span style="display:flex;"><span>           (network <span style="color:#e6db74">&#34;host&#34;</span>)
</span></span><span style="display:flex;"><span>           (ports
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;3000&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;80&#34;</span>))))))
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Why I Prefer VC Over Magit [Video]</title>
      <link>https://thanosapollo.org/posts/why-i-prefer-vc-over-magit/</link>
      <pubDate>Fri, 08 Nov 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/why-i-prefer-vc-over-magit/</guid>
      <description>Short video about VC &amp;amp; Magit</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve just uploaded a short video on why I prefer VC over Magit,
alongside a quick demo workflow with VC.</p>
<p>The video is available on youtube
<a href="https://www.youtube.com/watch?v=-pPkGWIfdqM">here</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Rewriting Gnosis: 0.4.0 release</title>
      <link>https://thanosapollo.org/posts/gnosis-0-4-0-release/</link>
      <pubDate>Wed, 07 Aug 2024 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-0-4-0-release/</guid>
      <description>Gnosis (γνῶσις), a spaced repetition system implementation for GNU Emacs</description>
      <content:encoded><![CDATA[<p>What&rsquo;s the most important thing for storing knowledge?</p>
<p>I&rsquo;d say proper organization of said knowledge, such as with decks for
each subject and meaningful tags linking related concepts together across
decks, making it easily searchable and accessible.</p>
<p>As I started adding more and more notes into gnosis, I found myself
wanting to adjust the review algorithm not only for decks but for tags
as well. This led me to overhaul the underlying architecture and
reimplement key concepts.</p>
<h2 id="key-changes-made">Key Changes Made</h2>
<ul>
<li>Redesigned <code>gnosis-dashboard</code> with a <em>home-page-like</em> buffer
displaying current activity stats such as review streak and today&rsquo;s
due notes.
<img loading="lazy" src="/images/gnosis-dashboard-03.png"></li>
<li>Rewritten gnosis algorithm:
<ul>
<li>Added <strong>gnosis-score</strong>, the current knowledge score for a note.</li>
<li>Added <strong>epignosis</strong> value, that indicates the knowledge accuracy
for a given note, as well as <strong>agnoia</strong> to indicate the lack of
knowledge for a note, those values will be used in <strong>anagnosis
events</strong>. <em>The &ldquo;indication&rdquo; is the translation of those words
from greek.</em></li>
<li>Added special review events; <strong>Anagnosis</strong> &amp; <strong>Lethe</strong>
<ul>
<li><strong>Anagnosis</strong> refers to the recognition &amp; understanding of a
context, anagnosis events are triggered by either consecutive
failed or successful recalls. Depending on how it&rsquo;s triggered,
<strong>epignosis</strong> or <strong>agnoia</strong> will be applied to <strong>gnosis-score</strong></li>
<li><strong>Lethe</strong> refers to the forgetting of knowledge, it&rsquo;s triggered
by consecutive failures to recall an answer, upon this event the
next interval is set to 0</li>
</ul>
</li>
<li>Added <strong>amnesia</strong>, upon failing to recall a note, amnesia value is
used to determine the next interval.</li>
<li>Added <strong>proto</strong>, a list that consist of integers, indicating the
value for the first intervals. Proto list does not have a limit
on length.</li>
</ul>
</li>
<li>Re-implement the configuration for the above deck values, and added
the ability to do the same for tags. Tag configuration takes
priority over deck configuration.</li>
</ul>
<p><em>Example:</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-custom-values
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#39;</span>((:deck <span style="color:#e6db74">&#34;demo&#34;</span> (:proto (<span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">3</span>) :anagnosis <span style="color:#ae81ff">3</span> :epignosis <span style="color:#ae81ff">0.5</span> :agnoia <span style="color:#ae81ff">0.3</span> :amnesia <span style="color:#ae81ff">0.5</span> :lethe <span style="color:#ae81ff">3</span>))
</span></span><span style="display:flex;"><span>    (:tag <span style="color:#e6db74">&#34;demo-concept&#34;</span> (:proto (<span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span>) :anagnosis <span style="color:#ae81ff">3</span> :amnesia <span style="color:#ae81ff">0.7</span>))))
</span></span></code></pre></div><p>A note under the deck <em>demo</em> tagged with <em>demo-concept</em> will have the
demo deck values with the exception of:</p>
<ul>
<li><code>proto</code> value set to <code>(1 2)</code></li>
<li><code>amnesia</code> value set to <code>0.7</code></li>
</ul>
<p>For notes that have multiple tags, the maximum value is retained for
most parameters. However, <code>anagnosis</code> and <code>lethe</code> will retain the
minimum value.</p>
<h2 id="next-features-on-the-horizon">Next features on the horizon</h2>
<ul>
<li>Org mode integration</li>
<li>Deck export &amp; import</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Penicillins Presentation Summarized</title>
      <link>https://thanosapollo.org/posts/penicillins-presentation/</link>
      <pubDate>Wed, 12 Jun 2024 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/penicillins-presentation/</guid>
      <description>&lt;p&gt;A summarized version of my presentation on &lt;a href=&#34;https://en.wikipedia.org/wiki/Penicillin&#34;&gt;penicillins&lt;/a&gt; for my
pharmacology course.  Penicillins are β-lactams antibacterial drugs
that inhibit bacterial cell wall synthesis, thus categorized as
bactericidal.&lt;/p&gt;
&lt;h2 id=&#34;history&#34;&gt;History&lt;/h2&gt;
&lt;p&gt;Discovered by Alexander Fleming, in 1928. Accidentally observed that
&lt;em&gt;staphylococci&lt;/em&gt; did not grow around the mold of Penicillium
rubens.&lt;/p&gt;
&lt;p&gt;However, it wasn&amp;rsquo;t until 1941 the Australian pathologist Howard
Florey and German-born British biochemist Ernst Boris Chain
successfully developed a method to produce a pure form of penicillin
on a large scale.  This breakthrough eventually led to mass production,
with penicillin becoming widely available by the end of World War
II.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A summarized version of my presentation on <a href="https://en.wikipedia.org/wiki/Penicillin">penicillins</a> for my
pharmacology course.  Penicillins are β-lactams antibacterial drugs
that inhibit bacterial cell wall synthesis, thus categorized as
bactericidal.</p>
<h2 id="history">History</h2>
<p>Discovered by Alexander Fleming, in 1928. Accidentally observed that
<em>staphylococci</em> did not grow around the mold of Penicillium
rubens.</p>
<p>However, it wasn&rsquo;t until 1941 the Australian pathologist Howard
Florey and German-born British biochemist Ernst Boris Chain
successfully developed a method to produce a pure form of penicillin
on a large scale.  This breakthrough eventually led to mass production,
with penicillin becoming widely available by the end of World War
II.</p>
<p>It revolutionized the medical world, providing an effective
treatment for many bacterial infections, and earning Fleming, Florey,
and Chain the 1945 Nobel Prize in Physiology of Medicine.</p>
<p><em>Fun fact</em>:</p>
<blockquote>
<p><a href="https://en.wikipedia.org/wiki/Amalia_Fleming">Amalia Fleming</a>, the wife of Alexander Fleming, was a Greek physician &amp;
politician that aided the <a href="https://en.wikipedia.org/wiki/Greek_resistance">Greek Resistance</a> against the occupation of
Axis powers.</p>
</blockquote>
<h2 id="overview">Overview</h2>
<h3 id="structure">Structure</h3>
<p>Structurally, this class of beta-lactams particularly possesses a
distinct 4-membered beta-lactam ring, in addition to a thiazolide ring
and an R side chain.</p>
<p>The main distinguishing feature between variants within this family is
the <em>R substituent</em>.  This side chain is connected to the
6-aminopenicillanic acid residue and results in <em>variations</em> in the
antimicrobial spectrum, stability, and susceptibility to beta-lactamases
of each individual bactericidal drug.</p>
<h2 id="mechanism-of-action">Mechanism of Action</h2>
<p>The mechanism of action for Penicillins primarily focuses on
<strong>inhibiting bacterial cell wall synthesis</strong>, an essential process for
bacterial growth and survival.  The beta-lactam ring in penicillins mimics
the D-Alanyl-D-Alanine terminal structures found in the precursors of
bacterial cell walls.  This mimicry allows penicillins to bind to
penicillin-binding proteins (<em>PBPs</em>), which are enzymes involved in cell
wall synthesis.</p>
<p>Upon binding, the normal function of the PBPs is disrupted, leading to
faulty cell wall production.  As a result of these alterations in cell
wall integrity, bacteria can undergo lysis due to imbalances in
cellular osmotic pressure, thus achieving the bactericidal effect of
penicillins.</p>
<p>Moreover, the R side chain of penicillin allows for its diverse range
of action against different types of bacteria, due to variations
affecting the antimicrobial spectrum, stability, and resistance to
beta-lactamases.</p>
<h2 id="antibacterial-spectrum-and-types">Antibacterial Spectrum &amp; Types</h2>
<h3 id="naturally-occurring">Naturally occurring</h3>
<p><em>Obtained from fermentations of the fungus Penicillum chrysogenum</em></p>
<h4 id="penicillin-g">Penicillin G</h4>
<p>Penicillin G is a crucial member of the penicillin family due to its
unique characteristics. It doesn&rsquo;t absorb well through the
gastrointestinal tract, so it is predominantly used intravenously. Due
to its selectivity, most species of Streptococci show sensitivity
towards it, leading to effective infection control in most
cases.</p>
<p>However, it is worth noting that the majority of Staphylococcus aureus
species have developed resistance to it, rendering the penicillin G
less effective in such situations.</p>
<p>Despite this, penicillin G is the drug of choice when it comes to the
treatment of gas gangrene brought about by Clostridium perfringens.
Similarly, its efficacy is demonstrated in the treatment of infections
like syphilis caused by Treponema.</p>
<p>Penicillin G is effective in treating syphilis, one essential thing to
note is the potential occurrence of the Jarisch-Herxheimer
reaction.  This is a systemic reaction, often observed within the first
few hours of therapy in patients treated for syphilis.  Symptoms may
include fever, chills, headache, and myalgia. While it can be
alarming, the reaction is typically self-limiting and can be managed
symptomatically.</p>
<h4 id="penicillin-v">Penicillin V</h4>
<p>Penicillin V, a less potent variant of Penicillin G, is typically
administered orally due to its acid-stable properties. This makes it
highly effective and safe for gastric administration.</p>
<p>While it delivers a milder impact compared to Penicillin G, it is
widely utilized in treating less severe infections, making it an
essential component in the spectrum of Penicillins.</p>
<h3 id="antistaphylococcal-penicillins">Antistaphylococcal penicillins</h3>
<p><em>Also known as penicillinase-resistant penicillins</em>, are a subset of
penicillins that are particularly effective against Staphylococcus
infections.  Unlike regular penicillins, they are resistant to
penicillinase (beta-lactamase) enzymes secreted by certain bacteria to
nullify penicillins&rsquo; bactericidal activity.</p>
<p>Methicillin, although no longer commonly used due to allergic
reactions and resistance, was one of the first of these
penicillins.  It paved the way for other, more robust,
antistaphylococcal penicillins.</p>
<p><strong>Flucloxacillin</strong>, <strong>oxacillin</strong>, and <strong>dicloxacillin</strong>, largely have replaced
methicillin.</p>
<p>They all have a similar mechanism of action, they inhibit bacterial
cell wall synthesis by binding to penicillin-binding proteins,
ultimately leading to bacterial cell death. These medications are
primarily used for skin and soft tissue infections caused by
Staphylococcus aureus, including cellulitis and impetigo.</p>
<p>Although they are generally well-tolerated, they can cause side
effects like gastrointestinal issues and allergic reactions.  These
drugs should be used with caution in patients with a history of
penicillin allergy and kidney disease.  Oxacillin and dicloxacillin
are often more desirable due to their ability to be administered
orally compared to flucloxacillin, which is typically given
parenterally.</p>
<h3 id="aminopenicillins">Aminopenicillins</h3>
<p>They are classified as broad-spectrum antibiotics due to their utility
against both gram-negative and gram-positive bacteria. Amoxicillin and
Ampicillin are common examples of Aminopenicillins.</p>
<h4 id="ampicillin">Ampicillin</h4>
<p>Ampicillin, exhibits similar antibacterial spectrum as amoxicillin but
differs crucially in its pharmacokinetics and mode of administration.</p>
<p>While it is effective against many Gram-positive and select
Gram-negative bacteria, it lacks stability in gastric acid, which can
lower its systemic absorption when taken orally.</p>
<p>Therefore, it is frequently administered intravenously or
intramuscularly in a clinical setting.  Ampicillin’s spectrum can be
notably widened by the co-administration of a beta-lactamase inhibitor
such as sulbactam.</p>
<h4 id="amoxicillin">Amoxicillin</h4>
<p>Distinguished by its wide usage in treating a variety of bacterial
infections.  It is favored for its broad-spectrum antibacterial
activity against both Gram-positive and Gram-negative microbes,
including H. influenzae, E. coli, and S. pneumoniae.  Its enhanced
stability against gastric acid ensures a higher systemic absorption
when administered orally, a major advantage over its contemporaries.</p>
<p>Additionally, amoxicillin is often prescribed in combination with
clavulanic acid, a beta-lactamase inhibitor, to tackle bacteria
producing beta-lactamase enzymes which can otherwise inactivate
amoxicillin.</p>
<h3 id="extended-spectrum">Extended-spectrum</h3>
<h4 id="piperacillin">Piperacillin</h4>
<p>Piperacillin is a potent extended-spectrum penicillin developed to
counter the rise of resistant bacterial infections.</p>
<p>It has broader antibacterial activity than most other penicillins,
particularly effective against Gram-negative bacteria including
<strong>pseudomonas aeruginosa</strong>.  Piperacillin also has superior activity
against enterococci, however, it remains ineffective against
methicillin-resistant Staphylococcus aureus (MRSA). It functions by
inhibiting bacterial cell wall synthesis, leading to cell death.</p>
<blockquote>
<p>Piperacillin is often combined with tazobactam, a beta-lactamase
inhibitor, to overcome resistance caused by beta-lactamase enzymes.</p>
</blockquote>
<h4 id="ticarcillin">Ticarcillin</h4>
<p>Ticarcillin, another extended-spectrum penicillin, has a similar
mechanism to piperacillin, targeting bacterial cell wall synthesis.
But it differs from piperacillin in its antimicrobial spectrum.</p>
<p>It is less active against Gram-negative bacteria and has minimal
activity against pseudomonas aeruginosa. However, it is more effective
against staphylococci and streptococci bacteria.</p>
<blockquote>
<p>Ticarcillin is frequently used with a beta-lactamase inhibitor,
clavulanic acid, to combat beta-lactamase-associated resistance.</p>
</blockquote>
<h4 id="comparison">Comparison</h4>
<p>Comparing both, ticarcillin has a lower sodium load which may be
beneficial in patients requiring sodium restriction.</p>
]]></content:encoded>
    </item>
    <item>
      <title>XMPP: Getting started with the universal communication standard</title>
      <link>https://thanosapollo.org/posts/moving-to-xmpp/</link>
      <pubDate>Tue, 30 Apr 2024 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/moving-to-xmpp/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://xmpp.org/&#34;&gt;XMPP&lt;/a&gt; is a libre decentralized collection of technologies, alternative
to closed communication services.  I&amp;rsquo;ve started self hosting my own
xmpp server, and begun moving people from my close circle there.  This
is a summary of my collection of notes that I made for XMPP thus far,
published as a short article.  If you are interested in learning more
on XMPP I recommend reading their official &lt;a href=&#34;https://xmpp.org/&#34;&gt;website&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;what-is-xmpp&#34;&gt;What is XMPP?&lt;/h2&gt;
&lt;p&gt;XMPP stands for eXtensible Messaging and Presence Protocol, it&amp;rsquo;s a set
of libre technologies that can be used for communication services,
such as instant messaging, voice &amp;amp; video calls as well as file
transfers.  This is done by routing &lt;code&gt;XML&lt;/code&gt; data.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><a href="https://xmpp.org/">XMPP</a> is a libre decentralized collection of technologies, alternative
to closed communication services.  I&rsquo;ve started self hosting my own
xmpp server, and begun moving people from my close circle there.  This
is a summary of my collection of notes that I made for XMPP thus far,
published as a short article.  If you are interested in learning more
on XMPP I recommend reading their official <a href="https://xmpp.org/">website</a>.</p>
</blockquote>
<h2 id="what-is-xmpp">What is XMPP?</h2>
<p>XMPP stands for eXtensible Messaging and Presence Protocol, it&rsquo;s a set
of libre technologies that can be used for communication services,
such as instant messaging, voice &amp; video calls as well as file
transfers.  This is done by routing <code>XML</code> data.</p>
<p>XMPP operates similarly to HTTP, with the client initiating a
communication socket to an XMPP server and maintaining it open for the
entirety of the client&rsquo;s active session.</p>
<blockquote>
<p>XMPP was originally developed in the Jabber community to provide an
open decentralized alternative to closed messaging services.</p>
</blockquote>
<p>XMPP is used by a few popular platforms, these include <a href="https://medium.com/@rajendra_51543/how-whatsapp-works-197bfc6d6b95">WhatsApp</a>, Facebook
Messenger &amp; Jitsi.</p>
<h2 id="why-should-you-use-xmpp">Why should you use XMPP?</h2>
<p>For me, the primary appeal of XMPP lies in its interoperability,
versatility, and extensibility. Via transports or gateways, XMPP
enables a seamless connection with communities across various
platforms <em>including IRC, Matrix, WhatsApp, Telegram</em> all from a
single client.</p>
<p>Furthermore, the decentralized nature of XMPP is <strong>designed</strong> for self
hosting, <em>with minimal resources</em>.  This gives me the freedom to
establish and manage my own server, creating an ecosystem that
provides me with freedom &amp; respects my rights, to which I can bring my
family and friends.</p>
<h3 id="how-to-communicate-with-irc-and-matrix-using-xmpp">How to communicate with IRC &amp; Matrix using XMPP?</h3>
<p>You can use a gateway that connects to your desired
platform/protocol. For example, for IRC you&rsquo;d use <a href="https://github.com/louiz/biboumi">biboumi</a> or <a href="https://github.com/matrix-org/matrix-bifrost">btifrost</a>
for Matrix.</p>
<blockquote>
<p>There are publicly available gateways, for example you can use the the
biboumi gateway from <a href="https://jabberfr.org/">jabberfr.org</a> to connect to the emacs IRC channel
in libera.chat like this <code>#emacs%irc.libera.chat@irc.jabberfr.org</code></p>
</blockquote>
<h2 id="self-hosting-an-xmpp-server">Self hosting an XMPP server</h2>
<p>If you are not interested in self hosting an XMPP server, refer to
this <a href="https://list.jabber.at/">list</a> to find servers to register to.</p>
<h3 id="ejabberd">ejabberd</h3>
<p>I opted to use <a href="https://www.ejabberd.im/">ejabberd</a> server for my setup, which I found really
simple to setup with voice &amp; video calls.</p>
<p>Setting up an ejabberd server is that simple that it does not really
require instructions.  I&rsquo;d recommend you use their <a href="https://docs.ejabberd.im/admin/install/binary-installer/#linux-run-installer">RUN Installer</a> or if
you are on debian/fedora to check out their <a href="https://github.com/processone/ejabberd/releases">releases</a> for an rpm/deb
package.</p>
<p>Other server &amp; client options can be found <a href="https://xmpp.org/software/?platform=linux">here</a>.</p>
<h2 id="xmpp-clients">XMPP clients</h2>
<p>All in all, XMPP offers user friendly clients in all platforms, that
everyone can use, as always refer <a href="https://xmpp.org/software/?platform=linux">here</a> for up-to-date recommendations.</p>
<p>This is what I <em>personally</em> have been using this past week with XMPP &amp;
recommend.</p>
<h3 id="mobile">Mobile</h3>
<ul>
<li>For android, I&rsquo;d recommend to use <a href="https://f-droid.org/packages/com.cheogram.android/">cheogram</a>, it&rsquo;s based on
<a href="https://conversations.im/">conversations</a> with a few visual tweaks and additional features.</li>
<li>For iOS, I&rsquo;ve installed <a href="https://monal-im.org/">Monal</a> to my friends &amp; family.  I&rsquo;m not sure
if it&rsquo;s the best one available since the iOS ecosystem is foreign to
me, but the people I&rsquo;ve installed it on found it pleasant to use.</li>
</ul>
<h3 id="desktop">Desktop</h3>
<ul>
<li>I&rsquo;d recommend <a href="https://dino.im/">Dino</a>, it&rsquo;s been really easy to use with full
support of most xmpp features (<a href="https://en.wikipedia.org/wiki/OMEMO">OMEMO</a> encryption etc.)</li>
<li>There is also <a href="https://codeberg.org/emacs-jabber/emacs-jabber">emacs-jabber</a>, an emacs jabber extension, that
unfortunately does not support any kind of encryption.  It&rsquo;s decent
for public unencrypted channels.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Jellyfin: Powering the Self-Hosted Media Revolution</title>
      <link>https://thanosapollo.org/posts/jellyfin-setup/</link>
      <pubDate>Thu, 04 Apr 2024 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/jellyfin-setup/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jellyfin.org/&#34;&gt;Jellyfin&lt;/a&gt; is my favorite service to self host, I&amp;rsquo;ve been using it for
movies &amp;amp; books and I&amp;rsquo;d even consider using it for photos if not for
&lt;a href=&#34;https://thanosapollo.org/posts/immich-setup/&#34;&gt;Immich&lt;/a&gt;.  Jellyfin is really popular as a self hosted streaming service
for movies &amp;amp; TV shows, since those platforms suffer heavily from
&lt;a href=&#34;https://en.wikipedia.org/wiki/Enshittification&#34;&gt;enshittification&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Jellyfin can do much more than stream your favorite movies &amp;amp; TV
shows.  Whether you&amp;rsquo;re a movie enthusiast, music lover, or photo
fanatic, Jellyfin has got you covered.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://jellyfin.org/">Jellyfin</a> is my favorite service to self host, I&rsquo;ve been using it for
movies &amp; books and I&rsquo;d even consider using it for photos if not for
<a href="/posts/immich-setup/">Immich</a>.  Jellyfin is really popular as a self hosted streaming service
for movies &amp; TV shows, since those platforms suffer heavily from
<a href="https://en.wikipedia.org/wiki/Enshittification">enshittification</a>.</p>
<blockquote>
<p>Jellyfin can do much more than stream your favorite movies &amp; TV
shows.  Whether you&rsquo;re a movie enthusiast, music lover, or photo
fanatic, Jellyfin has got you covered.</p>
</blockquote>
<h2 id="what-is-jellyfin">What is Jellyfin</h2>
<p>Jellyfin is a self-hosted multimedia service, which gives you full
control of <strong>your</strong> media.  It&rsquo;s one of the easiest and most useful
services to self host, refer to Jellyfin&rsquo;s <a href="https://jellyfin.org/docs/general/installation/">installation instructions</a>
for up-to-date information.</p>
<h3 id="why-jellyfin">Why Jellyfin</h3>
<p>Jellyfin&rsquo;s key strength is its multi-platform support.  Unlike other
media services like <a href="https://github.com/Dusk-Labs/dim">Dim</a>, a rust media manager, jellyfin supports a
wide range of platforms including iOS &amp; Android.  This make it easy to
access your content, from any device, at any time.</p>
<h3 id="accessing-jellyfin">Accessing Jellyfin</h3>
<p>Jellyfin will be available by default on your local network on
<code>&lt;host:8096&gt;</code>.  I recommend using a VPN service like <a href="https://tailscale.com/">tailscale</a> or
<a href="https://www.pivpn.io/">pivpn</a> to access your jellyfin instance when you are not on your local
network.</p>
<h2 id="jellyfin-as-a-movie-and-tv-show-streaming-service">Jellyfin As A Movie &amp; TV Show Streaming Service</h2>
<p>Streaming services are going through a weird phase, an era of service
specialization has begun, also know as <em>platform decay</em>.  Long gone
are the days when you subscribe to just one streaming service, it has
become a multi-platform journey.</p>
<p>With jellyfin you can bypass geo-restrictions &amp; have complete control
&amp; autonomy.  Today&rsquo;s commercial streaming services seem to offer a
deteriorating user experience, making it increasingly difficult to
justify their subscription fees.</p>
<blockquote>
<p>Depending on how you access your Jellyfin instance &amp; the hardware you
are using, you can have an improved performance, especially when
compared to <em>&ldquo;free&rdquo;</em> streaming services.</p>
</blockquote>
<h2 id="jellyfin-as-a-music-streaming-service">Jellyfin As A Music Streaming Service</h2>
<p>Everybody is making posts about Jellyfin as a Plex/Netflix
alternative, but it&rsquo;s also an even better music player on mobile than
Spotify as well, thanks to <a href="https://github.com/dkanada/gelli">Gelli</a>, which offers a native music player
for Android.</p>
<p>My music collection is precious to me, unfortunately with services
like Spotify you do not own it, you cede control over your collection.
Spotify, vast in its reach and scale, can alter its terms &amp; user
experience at will, such as removing your favorite artists albums or
adjusting it&rsquo;s algorithm recommendations to maximize their profit
while disregarding your own taste.</p>
<p>Jellyfin is self-hosted, thereby retaining all choices and decisions
lie squarely within your ambit of control.</p>
<h2 id="jellyfin-as-a-digital-library">Jellyfin As A Digital Library</h2>
<p>My digital library is <strong>crucial</strong> to me.  Accessibility is key, whether
at my university&rsquo;s library, coffee shop, or even at a lecture hall.
Jellyfin facilitates this seamlessly.  While the content viewer might
not cater to my preferences, I mitigate this by downloading the
required book and reading it in Emacs using <a href="https://github.com/vedang/pdf-tools">pdf-tools</a> or <a href="https://depp.brause.cc/nov.el/">nov.el</a>.</p>
<h2 id="downsides-of-using-jellyfin">Downsides Of Using Jellyfin</h2>
<p>Jellyfin&rsquo;s downside is the potential reliance it might inadvertently
create on file sharing services.  Depending on the communities you
visit, your experience might vary; you might come across toxic
individuals or friendly people that share your passion.</p>
<p>I recommend reading <a href="https://torrentfreak.com/">torrentfreak</a> to keep yourself up to date on recent
developments and suggestions.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Jellyfin is a powerful self-hosting multimedia solution that allows
users to manage their movie library, music collection &amp; digital
library all within a single service across multiple platforms.</p>
<p>The main downside of using Jellyfin is the reliance on 3rd party file
sharing services.  Although, relying on a commercial streaming service
is an even worse option these days.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Immich: Self-hosted Photo &amp; Video Management</title>
      <link>https://thanosapollo.org/posts/immich-setup/</link>
      <pubDate>Mon, 25 Mar 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/immich-setup/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve recently transitioned to a pixel phone with GrapheneOS as my
primary device, moving from an iPhone.  The only thing that I was
missing is having my photos be in sync across all of my devices using
iCloud, but despite the convenience of Apple&amp;rsquo;s iCloud service for
syncing photos across devices, it frequently disregards user rights
and privacy.  Thankfully, &lt;a href=&#34;https://immich.app/&#34;&gt;Immich&lt;/a&gt; offers a self-hosted and
enhanced alternative while respecting my privacy &amp;amp; user rights.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve recently transitioned to a pixel phone with GrapheneOS as my
primary device, moving from an iPhone.  The only thing that I was
missing is having my photos be in sync across all of my devices using
iCloud, but despite the convenience of Apple&rsquo;s iCloud service for
syncing photos across devices, it frequently disregards user rights
and privacy.  Thankfully, <a href="https://immich.app/">Immich</a> offers a self-hosted and
enhanced alternative while respecting my privacy &amp; user rights.</p>
<p>Setting up immich is quite simple, just follow the official
<a href="https://immich.app/docs/overview/introduction">documentation</a>.  They even offer an <a href="https://immich.app/docs/install/script">installation script</a>.</p>
<h2 id="recommendations">Recommendations</h2>
<p>I advise against using services like Cloudflare Tunnel to make Immich
accessible publicly for security and privacy concerns. Instead,
consider using a VPN service such as tailscale/headscale for a more
secure &amp; convenient setup.</p>
<p>If you are using iCloud for your photos, there is a <a href="https://github.com/immich-app/immich/issues/3842#issuecomment-2008718176">memory leak bug</a>
that will cause the iOS app to crash when uploading large amounts of
media files.  Either first download all your photos from iCloud &amp; then
upload to them Imminch, or &ldquo;babysit&rdquo; your phone while it&rsquo;s uploading.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Why Emacs will NEVER be popular</title>
      <link>https://thanosapollo.org/posts/emacs-will-never-be-popular/</link>
      <pubDate>Mon, 11 Mar 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-will-never-be-popular/</guid>
      <description>&lt;p&gt;Emacs is my ride or die software, where I do all my computing.  If not
for Emacs, I wouldn&amp;rsquo;t give a byte about computers.  Moved to GNU/Linux
just for Emacs. But let&amp;rsquo;s face it, Emacs will forever swim against the
current. Just like Gentoo, it&amp;rsquo;s too hardcore for the mainstream. To
vibe with it or not, that&amp;rsquo;s the 1 million dollar question.&lt;/p&gt;
&lt;h2 id=&#34;possible-solutions&#34;&gt;Possible Solutions&lt;/h2&gt;
&lt;p&gt;Emacs needs distributions to shine in this modern digital landscape
where everything should &amp;ldquo;just work&amp;rdquo; Distros like &lt;a href=&#34;https://github.com/doomemacs/doomemacs&#34;&gt;Doom Emacs&lt;/a&gt; can flex
the power of Emacs, enticing even those who can&amp;rsquo;t define it.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Emacs is my ride or die software, where I do all my computing.  If not
for Emacs, I wouldn&rsquo;t give a byte about computers.  Moved to GNU/Linux
just for Emacs. But let&rsquo;s face it, Emacs will forever swim against the
current. Just like Gentoo, it&rsquo;s too hardcore for the mainstream. To
vibe with it or not, that&rsquo;s the 1 million dollar question.</p>
<h2 id="possible-solutions">Possible Solutions</h2>
<p>Emacs needs distributions to shine in this modern digital landscape
where everything should &ldquo;just work&rdquo; Distros like <a href="https://github.com/doomemacs/doomemacs">Doom Emacs</a> can flex
the power of Emacs, enticing even those who can&rsquo;t define it.</p>
<p>Most people start with a text editor and never bother looking for
alternatives.  Even Lisp learners typically skip Emacs as a starting
point.  If not them, then who?</p>
<p>An Emacs distribution that just works would draw newcomers or at least
be the editor that you can drop on someone to learn programming.
Possible also something finely tuned for academics &amp; wordsmiths with
org-mode.</p>
<h2 id="popularity-shmopularity">Popularity shmopularity!</h2>
<p>Popularizing Emacs goes beyond just boosting its own fame; it&rsquo;s about
spreading the gospel of the GNU philosophy &amp; Lisp programming that
Emacs embodies.</p>
<p>We&rsquo;re not just promoting a tool, but a mindset and a way of thinking
that challenges the status quo in the world.  Embracing Emacs means
embracing a hacker ethos of freedom.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Cloudflare Tunnel: Bye Bye VPS Services!</title>
      <link>https://thanosapollo.org/posts/bye-bye-vps/</link>
      <pubDate>Sun, 10 Mar 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/bye-bye-vps/</guid>
      <description>&lt;p&gt;VPS services, the pinnacle of freedom in the digital world!  Nothing
quite beats the thrill of entrusting your data and services to a
mysterious cloud entity, all while relinquishing control over your
hardware.  And do not forget the joy of relying on a third-party
cloud provider for your hosting needs, that may send you a &lt;a href=&#34;https://old.reddit.com/r/webdev/comments/1b14bty/netlify_just_sent_me_a_104k_bill_for_a_simple/&#34;&gt;104K bill&lt;/a&gt;
for your static site.  Who needs to own their hardware anyway?&lt;/p&gt;
&lt;h2 id=&#34;my-new-setup&#34;&gt;My new setup&lt;/h2&gt;
&lt;p&gt;For the past ~6 months, I have been relying on a VPS service from
&lt;a href=&#34;https://www.ionos.com/&#34;&gt;Ionos&lt;/a&gt;, &lt;em&gt;which offers a decent service for it&amp;rsquo;s price plans&lt;/em&gt;, to host
this site &amp;amp; my git server, as well as to occasionally port forward
media services such as jellyfin using an ssh tunnel.  This weekend, I
opted to migrate to an old thinkpad that I had collecting dust plus
&lt;a href=&#34;https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/&#34;&gt;cloudflare tunnel&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>VPS services, the pinnacle of freedom in the digital world!  Nothing
quite beats the thrill of entrusting your data and services to a
mysterious cloud entity, all while relinquishing control over your
hardware.  And do not forget the joy of relying on a third-party
cloud provider for your hosting needs, that may send you a <a href="https://old.reddit.com/r/webdev/comments/1b14bty/netlify_just_sent_me_a_104k_bill_for_a_simple/">104K bill</a>
for your static site.  Who needs to own their hardware anyway?</p>
<h2 id="my-new-setup">My new setup</h2>
<p>For the past ~6 months, I have been relying on a VPS service from
<a href="https://www.ionos.com/">Ionos</a>, <em>which offers a decent service for it&rsquo;s price plans</em>, to host
this site &amp; my git server, as well as to occasionally port forward
media services such as jellyfin using an ssh tunnel.  This weekend, I
opted to migrate to an old thinkpad that I had collecting dust plus
<a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/">cloudflare tunnel</a>.</p>
<p>Cloudflare tunnel is ideal for securely connecting a self hosted web
server to Cloudflare&rsquo;s global network.  But be aware that cloudflare
can decrypt your traffic.  I do not recommend using cloudflare
tunnel to host sensitive information, or to share large media files.</p>
<p>To share media with friends, I use <a href="https://tailscale.com/">tailscale</a>, I plan in the future to
host <a href="https://headscale.net/">headscale</a>, a self hosted implementation of tailscale.  Tailscale
is a zero config VPN, you can add your family &amp; friends to your
account or just &ldquo;funnel&rdquo; content to a public address to give someone
quick access.</p>
<h2 id="transition-tips">Transition Tips</h2>
<p>First of all, evaluate your current VPS usage and identify which
services can be easily self hosted.  I&rsquo;d recommend to start slowly
migrating your services to your own hardware &amp; use ssh tunnel for port
forwarding.</p>
<p>Test out cloudflare tunnel, tailscale and other similar services until you
find the one you like the most.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Emacs Email Management | Setup Guide for mu4e &amp; isync</title>
      <link>https://thanosapollo.org/posts/mu4e-guide/</link>
      <pubDate>Mon, 29 Jan 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/mu4e-guide/</guid>
      <description>Managing emails with emacs, using mu4e &amp;amp; isync.</description>
      <content:encoded><![CDATA[<p>Email, hate it or love it, we all have to deal with it. Thankfully,
thanks to Emacs &amp; <a href="https://github.com/djcb/mu">mu4e</a> you can have a
productive and, dare I say, fun time working with emails.</p>
<h2 id="about">About</h2>
<p>In this guide I will guide you through setting up mu4e with multiple
accounts, using isync &amp; mu, as well as the basics of how to
incorporate mu4e into your workflow, plus tips &amp; tricks like using
mu4e actions to apply git patches.</p>
<p>To follow this guide, make sure to enable IMAP/SMTP access for your
email account. The steps to enable this may vary depending on your
specific email provider, so I won&rsquo;t cover that in this guide.</p>
<h2 id="why-mu4e">Why mu4e?</h2>
<p>There are multiple options available in GNU Emacs for managing emails,
such as rmail, gnus, notmuch, and mu4e.</p>
<p>Each of these options has its own complexities, depending on your
specific use case.</p>
<p>In my personal experience, I find mu4e to be preferable due to its
ease of setup, particularly when dealing with multiple accounts.</p>
<h2 id="installing-mu-isync">Installing MU &amp; isync</h2>
<p>To get started, install <strong>mu</strong> &amp; <strong>isync</strong></p>
<ul>
<li>Arch Linux</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo pacman -S mu isync
</span></span></code></pre></div><ul>
<li>Gentoo</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo emerge -av mu isync
</span></span></code></pre></div><p><code>NOTE</code>: Make sure you to use <code>emacs</code> USEFLAG for mu</p>
<p>If <code>mu</code> is not packaged for your distro, I recommend changing to a new
one. But if you insist, you might have success installing mu from
source, using
<a href="https://github.com/radian-software/straight.el">straight.el</a>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(straight-use-package <span style="color:#e6db74">&#39;mu4e</span>)
</span></span></code></pre></div><h2 id="setting-up-mbsync">Setting up mbsync</h2>
<p>Edit your configuration: <code>~/.mbsyncrc</code></p>
<h3 id="example-setup-for-fastmail">Example setup for Fastmail:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>IMAPAccount fastmail
</span></span><span style="display:flex;"><span>Host imap.fastmail.com
</span></span><span style="display:flex;"><span>Port 993
</span></span><span style="display:flex;"><span>User myaccount@fastmail.com
</span></span><span style="display:flex;"><span>PassCmd &#34;emacsclient -e &#39;(password-store-get-field \&#34;fastmail.com/myaccount@fastmail.com\&#34; \&#34;smtp\)&#39;&#34;
</span></span><span style="display:flex;"><span>SSLType IMAPS
</span></span><span style="display:flex;"><span>SSLVersions TLSv1.2
</span></span><span style="display:flex;"><span>CertificateFile /etc/ssl/certs/ca-certificates.crt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>IMAPStore fastmail-remote
</span></span><span style="display:flex;"><span>Account fastmail
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>MaildirStore fastmail-local
</span></span><span style="display:flex;"><span>Path ~/Mail/Fastmail/
</span></span><span style="display:flex;"><span>Inbox ~/Mail/Fastmail/Inbox
</span></span><span style="display:flex;"><span>Trash ~/Mail/Fastmail/Trash/
</span></span><span style="display:flex;"><span>SubFolders Verbatim
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Channel fastmail
</span></span><span style="display:flex;"><span>Far :fastmail-remote:
</span></span><span style="display:flex;"><span>Near :fastmail-local:
</span></span><span style="display:flex;"><span>Patterns *
</span></span><span style="display:flex;"><span>Expunge None
</span></span><span style="display:flex;"><span>CopyArrivalDate yes
</span></span><span style="display:flex;"><span>Sync All
</span></span><span style="display:flex;"><span>Create Both
</span></span><span style="display:flex;"><span>SyncState *
</span></span></code></pre></div><h3 id="example-setup-for-gmail">Example setup for Gmail:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>IMAPAccount gmail
</span></span><span style="display:flex;"><span>Host imap.gmail.com
</span></span><span style="display:flex;"><span>Port 993
</span></span><span style="display:flex;"><span>User myaccount@gmail.com
</span></span><span style="display:flex;"><span>PassCmd &#34;pass google/mygmail.com&#34;
</span></span><span style="display:flex;"><span>SSLType IMAPS
</span></span><span style="display:flex;"><span>SSLVersions TLSv1.2
</span></span><span style="display:flex;"><span>CertificateFile /etc/ssl/certs/ca-certificates.crt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>IMAPStore gmail-remote
</span></span><span style="display:flex;"><span>Account gmail
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>MaildirStore gmail-local
</span></span><span style="display:flex;"><span>Path ~/Mail/Account-GMAIL/
</span></span><span style="display:flex;"><span>SubFolders Verbatim
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Channel gmail
</span></span><span style="display:flex;"><span>Far :gmail-remote:
</span></span><span style="display:flex;"><span>Near :gmail-local:
</span></span><span style="display:flex;"><span>Patterns * ![Gmail]* &#34;[Gmail]/Sent Mail&#34; &#34;[Gmail]/Starred&#34; &#34;[Gmail]/All Mail&#34; &#34;[Gmail]/Trash&#34;
</span></span><span style="display:flex;"><span>Expunge None
</span></span><span style="display:flex;"><span>CopyArrivalDate yes
</span></span><span style="display:flex;"><span>Sync All
</span></span><span style="display:flex;"><span>Create Both
</span></span><span style="display:flex;"><span>SyncState *
</span></span><span style="display:flex;"><span>Settings you should adjust:
</span></span></code></pre></div><ul>
<li><code>PassCmd</code> this should output your account password. I personally use
pass as my password manager.</li>
</ul>
<p>In the fastmail example above I get my password with this emacs
function:</p>
<p><code>(password-store-get-field \&quot;fastmail.com/myaccount@fastmail.com\&quot; \&quot;smtp\)</code></p>
<p><code>password-store</code> is a pass front-end for Emacs.</p>
<p><code>NOTE</code>: You can instead of PassCmd, use Pass that just has your
password in plain text, but I do not recommend this for security
reasons.</p>
<ul>
<li>
<p><code>CertificateFile</code> - This location can vary based on your Linux distribution.</p>
</li>
<li>
<p><code>Patterns</code> - Defines which folders will be synced, I personally just
define my folders manually, similarly to the fastmail example.</p>
</li>
</ul>
<p>Feel free to define multiple accounts this way.</p>
<p>After configuring isync, start the initial sync by running this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ mbsync -a
</span></span></code></pre></div><h2 id="setting-up-mu-mu4e">Setting up mu &amp; mu4e</h2>
<p>First, you have to run the initial index.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mu init --maildir=~/Mail --my-address myaccount@fastmail.com
</span></span><span style="display:flex;"><span>mu index
</span></span></code></pre></div><p><code>NOTE</code>: You may add as many <code>--my-address</code> arguments you want.</p>
<p>Now, it&rsquo;s time to create your mu4e configuration for Emacs.</p>
<p>You may create this as a module, or just as part of your :config using use-package. I personally define variables in my init.el like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defvar is-desktop (<span style="color:#a6e22e">equal</span> (<span style="color:#a6e22e">system-name</span>) <span style="color:#e6db74">&#34;desktop-hostname&#34;</span>)) <span style="color:#75715e">;; your $HOSTNAME</span>
</span></span><span style="display:flex;"><span>(defvar is-laptop (<span style="color:#a6e22e">equal</span> (<span style="color:#a6e22e">system-name</span>) <span style="color:#e6db74">&#34;laptop-hostname&#34;</span>))
</span></span></code></pre></div><p>Create <code>~/.emacs.d/modules/thanos-mu4e.el</code> for the mu4e module
configuration. And add this to my init.el</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;~/.emacs.d/modules&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(when (or is-desktop is-laptop)
</span></span><span style="display:flex;"><span>  (require <span style="color:#e6db74">&#39;thanos-mu4e</span>))
</span></span></code></pre></div><p>This way I only load my mu4e configuration only when I&rsquo;m using my
laptop or desktop.</p>
<h2 id="loading-mu4e">Loading Mu4e</h2>
<p>Make sure <code>mu4e</code> is on load-path:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;/usr/share/emacs/site-lisp/mu4e/&#34;</span>) <span style="color:#75715e">;; path to mu4e</span>
</span></span><span style="display:flex;"><span>(require <span style="color:#e6db74">&#39;mu4e</span>)
</span></span></code></pre></div><h2 id="the-essentials">The essentials</h2>
<p>This is an example configuration to get started with mu4e using multiple accounts:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf mu4e-get-mail-command <span style="color:#e6db74">&#34;mbsync -a&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(when (and is-desktop (server-running-p))
</span></span><span style="display:flex;"><span>  (setf mu4e-update-interval (<span style="color:#a6e22e">*</span> <span style="color:#ae81ff">10</span> <span style="color:#ae81ff">60</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Snippet from EmacsWiki</span>
</span></span><span style="display:flex;"><span>(defun set-mu4e-context (context-name full-name mail-address signature)
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Return a mu4e context named CONTEXT-NAME with :match-func matching
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    folder name CONTEXT-NAME in Maildir. The context&#39;s </span><span style="color:#e6db74">`user-mail-address&#39;</span><span style="color:#e6db74">,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    </span><span style="color:#e6db74">`user-full-name&#39;</span><span style="color:#e6db74"> and </span><span style="color:#e6db74">`mu4e-compose-signature&#39;`smtpmail-smpt-server&#39;</span><span style="color:#e6db74"> is set to MAIL-ADDRESS
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    FULL-NAME SIGNATURE and SERVER respectively.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    Special folders are set to context specific folders.&#34;</span>
</span></span><span style="display:flex;"><span>  (let ((dir-name (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;/&#34;</span> context-name)))
</span></span><span style="display:flex;"><span>    (make-mu4e-context
</span></span><span style="display:flex;"><span>     :name context-name
</span></span><span style="display:flex;"><span>     <span style="color:#75715e">;; we match based on the maildir of the message</span>
</span></span><span style="display:flex;"><span>     :match-func
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">`</span>(lambda (msg)
</span></span><span style="display:flex;"><span>    (when msg
</span></span><span style="display:flex;"><span>      (string-match-p
</span></span><span style="display:flex;"><span>       <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;^&#34;</span> dir-name)
</span></span><span style="display:flex;"><span>       (mu4e-message-field msg :maildir))))
</span></span><span style="display:flex;"><span>     :vars
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">`</span>((user-mail-address    <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>mail-address)
</span></span><span style="display:flex;"><span>       (<span style="color:#a6e22e">user-full-name</span>       <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>full-name)
</span></span><span style="display:flex;"><span>       (mu4e-sent-folder     <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Sent&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-drafts-folder   <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Drafts&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-trash-folder    <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Trash&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-trash-folder    <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Starred&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-refile-folder   <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Archive&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-compose-signature <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>signature)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;Fixing duplicate UID errors when using mbsync and mu4e</span>
</span></span><span style="display:flex;"><span>(setf mu4e-change-filenames-when-moving <span style="color:#66d9ef">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(setf mu4e-maildir-shortcuts
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;/Fastmail/Inbox&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?f</span>)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;/Drafts&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?d</span>)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;/Sent&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?s</span>)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;/Gmail-Account/[Gmail]/All Mail&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?g</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(setf mu4e-contexts
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>       (make-mu4e-context
</span></span><span style="display:flex;"><span>    :name <span style="color:#e6db74">&#34;fastmail&#34;</span>
</span></span><span style="display:flex;"><span>    :match-func
</span></span><span style="display:flex;"><span>    (lambda (msg)
</span></span><span style="display:flex;"><span>      (when msg
</span></span><span style="display:flex;"><span>        (string-prefix-p <span style="color:#e6db74">&#34;/Fastmail&#34;</span> (mu4e-message-field msg :maildir))))
</span></span><span style="display:flex;"><span>    :vars <span style="color:#f92672">&#39;</span>((user-mail-address <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;username@fastmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">user-full-name</span>    <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;User Name&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-server <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;smtp.fastmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-service <span style="color:#f92672">.</span> <span style="color:#ae81ff">465</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-stream-type <span style="color:#f92672">.</span> ssl)
</span></span><span style="display:flex;"><span>        (mu4e-drafts-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Drafts&#34;</span>)
</span></span><span style="display:flex;"><span>        (mu4e-sent-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Sent&#34;</span>)
</span></span><span style="display:flex;"><span>        (mu4e-refile-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Archive&#34;</span>)
</span></span><span style="display:flex;"><span>        (mu4e-trash-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Trash&#34;</span>)))
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">;; You can comment out the second account.</span>
</span></span><span style="display:flex;"><span>       (make-mu4e-context
</span></span><span style="display:flex;"><span>    :name <span style="color:#e6db74">&#34;gmail&#34;</span>
</span></span><span style="display:flex;"><span>    :match-func
</span></span><span style="display:flex;"><span>    (lambda (msg)
</span></span><span style="display:flex;"><span>      (when msg
</span></span><span style="display:flex;"><span>        (string-prefix-p <span style="color:#e6db74">&#34;/Gmail-Account&#34;</span> (mu4e-message-field msg :maildir))))
</span></span><span style="display:flex;"><span>    :vars <span style="color:#f92672">&#39;</span>((user-mail-address <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;username@gmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">user-full-name</span>    <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;User Name&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-server <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;smtp.gmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-service <span style="color:#f92672">.</span> <span style="color:#ae81ff">465</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-stream-type <span style="color:#f92672">.</span> ssl)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(setf message-send-mail-function <span style="color:#e6db74">&#39;smtpmail-send-it</span>
</span></span><span style="display:flex;"><span>      mu4e-compose-signature <span style="color:#e6db74">&#34;My Signature&#34;</span>
</span></span><span style="display:flex;"><span>      mu4e-compose-context-policy <span style="color:#e6db74">&#39;ask</span>)
</span></span></code></pre></div><h2 id="extras">Extras</h2>
<h3 id="mu4e-actions">Mu4e actions</h3>
<p>Mu4e actions makes it really simple to work with git patches, this is
an example configuration you may like to use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf mu4e-view-actions
</span></span><span style="display:flex;"><span>      (delete-dups
</span></span><span style="display:flex;"><span>       (<span style="color:#a6e22e">append</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;gapply git patches&#34;</span> <span style="color:#f92672">.</span> mu4e-action-git-apply-patch)
</span></span><span style="display:flex;"><span>      (<span style="color:#e6db74">&#34;mgit am patch&#34;</span> <span style="color:#f92672">.</span> mu4e-action-git-apply-mbox)))))
</span></span></code></pre></div><h3 id="sign-your-emails-using-pgp">Sign your emails using pgp</h3>
<p>If you have setup your own pgp key, you may sign automatically all your emails using this hook:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">&#39;message-send-hook</span> <span style="color:#e6db74">&#39;mml-secure-message-sign-pgpmime</span>)
</span></span></code></pre></div><p>Take a look at the functions defined for <code>mml-mode-map</code> for more.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis (γνῶσις) First Release</title>
      <link>https://thanosapollo.org/posts/gnosis-release/</link>
      <pubDate>Tue, 16 Jan 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-release/</guid>
      <description>Gnosis (γνῶσις), a spaced repetition system implementation for GNU Emacs</description>
      <content:encoded><![CDATA[<p>Gnosis (γνῶσις) is a <a href="https://en.wikipedia.org/wiki/Spaced_repetition">spaced
repetition</a> system
(SRS) implementation for note taking and self testing, for <a href="https://www.gnu.org/software/emacs/">GNU
Emacs</a>.</p>
<p>Gnosis does not use flashcard type learning, instead it uses a binary
value to rate user input. Meaning you either know the right answer, or
you do not, no rating of your own is involved.</p>
<h2 id="about">About</h2>
<p>On my last post, <a href="http://thanosapollo.org/post/spaced-repetition-software-gripes/">Spaced Repetition Software
Gripes</a>,
I outlined a blueprint for what I consider to be the optimal design of
an SRS, that caters to <strong>my personal</strong> preferences.</p>
<p>So, I&rsquo;ve developed my own SRS, gnosis (γνῶσις), pronounced &ldquo;GNU-sis&rdquo;,
<em>meaning knowledge in Greek</em>. This SRS addresses the concerns that I
previously highlighted. Currently, I have found it to be highly
beneficial and, as a result, I decided to share it with all of you.</p>
<h3 id="differences-with-other-srs">Differences with other SRS</h3>
<p>Gnosis does not implement flashcard type review sessions where the
user rates his own answer on an arbitrary scale. Instead implements
&ldquo;note&rdquo; types that require user input. Some of these note types, like
the <code>MCQ</code> <em>multiple choice question</em>, even allow for simulating
real-life exams.</p>
<p>Unlike other SRS implementations for GNU Emacs, gnosis does not rely
on <code>org-mode</code>, which I&rsquo;ve found not to be an ideal option for a
database replacement. Instead opting for an
<a href="https://www.sqlite.org/index.html">sqlite</a> database with
<a href="https://en.wikipedia.org/wiki/Git">git</a> to track any changes made,
enabling efficient data management, manipulation and data integrity.</p>
<p>Furthermore, since Gnosis is built upon Emacs, with Emacs Lisp, it
offers a convenient and (hopefully) enjoyable experience for
customization according to your individual preferences.</p>
<p>However, one drawback of using Gnosis is that it is not currently
supported on mobile devices, as Emacs has yet to extend its
compatibility to such platforms.</p>
<h2 id="installation">Installation</h2>
<p>You can get gnosis from my personal git server
<a href="https://git.thanosapollo.org/gnosis">here</a> or using this <a href="https://git.sr.ht/~thanosapollo/gnosis">sourcehut
mirror</a>.</p>
<h3 id="straight.el">Straight.el</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(straight-use-package
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#39;</span>(gnosis :type git
</span></span><span style="display:flex;"><span>          :host <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>          :repo <span style="color:#e6db74">&#34;https://git.thanosapollo.org/gnosis&#34;</span>))
</span></span></code></pre></div><h3 id="manual">Manual</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ git clone https://git.thanosapollo.org/gnosis
</span></span></code></pre></div><p><em>Add this to your emacs configuration:</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;/path/to/gnosis&#34;</span>)
</span></span><span style="display:flex;"><span>(load-file <span style="color:#e6db74">&#34;~/path/to/gnosis.el&#34;</span>)
</span></span><span style="display:flex;"><span>(require <span style="color:#e6db74">&#39;gnosis</span>)
</span></span></code></pre></div><h2 id="adding-notes">Adding notes</h2>
<p>Creating notes for gnosis can be done with a simple
<code>M-x gnosis-add-note</code></p>
<p>Everything is done through the mini-buffer. My personal workflow takes
advantage of that by not really leaving <code>gnosis-add-note</code> prompt until
I finish studying a chapter/section, using
<a href="https://github.com/vedang/pdf-tools">pdf-tools</a> or
<a href="https://depp.brause.cc/nov.el/">nov.el</a>.</p>
<p><em>I think you won&rsquo;t need much guidance on creating notes for any note type, except <code>cloze</code>.</em></p>
<h3 id="creating-cloze-type-notes">Creating cloze type notes</h3>
<p>Cloze type note questions are formatted similarly to Anki&rsquo;s syntax, like so:
&gt; {c1:Cyproheptadine} is a(n) {c2:5-HT2} receptor antagonist used to treat {c2:serotonin syndrome}</p>
<p><em>NOTE</em>: You can also format clozes like Anki if you so prefer; e.g
<code>{{c1::Cyproheptadine}}</code></p>
<ul>
<li>
<p>For each <code>cX</code>-tag there will be created a cloze type note, the above
example creates 2 cloze type notes.</p>
</li>
<li>
<p>Each <code>cX</code> tag can have multiple clozes, but each cloze must be a
<em>UNIQUE</em> word (or a unique combination of words) in given note.</p>
</li>
</ul>
<h2 id="customizing-gnosis-algorithm">Customizing gnosis algorithm</h2>
<h3 id="gnosis-algorithm-interval"><code>gnosis-algorithm-interval</code></h3>
<p>This is a list of 2 numbers, for the first 2 intervals after a
successful review. For example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-algorithm-interval <span style="color:#f92672">&#39;</span>(<span style="color:#ae81ff">1</span> <span style="color:#ae81ff">3</span>))
</span></span></code></pre></div><p>After first successfully reviewing a note, you will see it again
tomorrow, if you successfully review said note again, the next review
will be after 3 days.</p>
<h3 id="gnosis-algorithm-ef"><code>gnosis-algorithm-ef</code></h3>
<p>This is the value of gnosis &ldquo;easiness factor&rdquo;, it&rsquo;s basically a list
that consists of 3 items. The first item is the increase factor, used
to increase the easiness factor upon successful review. Second item
refers to the decrease factor, used to decrease the easiness factor
upon an unsuccessful review. The third item is the (starting) total
easiness factor, used to calculate the next interval.</p>
<p>The basic&rsquo;s of how this is used is that it&rsquo;s being multiplied with the
last interval, e.g if you last reviewed a note 6 days ago, and the
easiness factor (total) of this note is 2.0, your next interval would
be 6 * 2.0 &amp; the next total ef will be 2.0 + increase-factor.</p>
<p>Example configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-algorithm-ef <span style="color:#f92672">&#39;</span>(<span style="color:#ae81ff">0.3</span> <span style="color:#ae81ff">0.3</span> <span style="color:#ae81ff">1.3</span>))
</span></span></code></pre></div><h3 id="gnsois-algorithm-ff"><code>gnsois-algorithm-ff</code></h3>
<p>This is the value of gnosis forgetting factor (ff), it needs to be a
floating number below 1. This is used to calculate the next interval
upon an unsuccessful review, by being multiplied with last interval.
If for a note with a value of last-interval of 6 days and a ff of 0.5,
upon an unsuccessful review the next interval will be in 6 * 0.5 days</p>
<p>Example configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-algorithm-ff <span style="color:#ae81ff">0.5</span>)
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Spaced Repetition Software Gripes</title>
      <link>https://thanosapollo.org/posts/spaced-repetition-software-gripes/</link>
      <pubDate>Tue, 09 Jan 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/spaced-repetition-software-gripes/</guid>
      <description>Issues with Spaced Repetition (Learning) Software &amp;amp; Announcement of Gnosis</description>
      <content:encoded><![CDATA[<p>In this post I&rsquo;m essentially publicizing my notes on spaced repetition
software, and announcing that I&rsquo;m working on
<a href="https://git.thanosapollo.org/gnosis">gnosis</a>, a spaced repetition
learning extension/package for GNU Emacs.</p>
<p>I should also note that I consider <a href="https://en.wikipedia.org/wiki/Spaced_repetition">Spaced
Repetition</a> to be a
cheat code for learning, <strong>that should be used by every student</strong>.</p>
<h2 id="what-is-spaced-repetition-learning">What is Spaced Repetition Learning</h2>
<p><a href="https://en.wikipedia.org/wiki/Spaced_repetition">Spaced Repetition</a>
is based on the following premise:
&gt; Repetitive exposure to information contributes to the elongation of memory retention.</p>
<p>Our cognitive faculties are inherently programmed to retain pertinent
information while discarding extraneous details, a process contingent
upon the frequency by which we encounter such information.</p>
<blockquote>
<p>TL;DR: The more frequently you are exposed to information, the longer you retain it</p>
</blockquote>
<h2 id="my-gripes-with-spaced-repetition-software">My &lsquo;gripes&rsquo; with spaced repetition software</h2>
<p>I have chosen to develop my own SRS (Spaced Repetition Software/System) instead
of relying on existing, well-established ones. Through my
implementation called &ldquo;gnosis&rdquo; (GNOH-sis, meaning knowledge in Greek)
I aim to address and overcome the challenges and limitations
associated with current SRS solutions. With gnosis, I hope to resolve
most, if not all, of these issues and provide a more refined and
<strong>advanced</strong> learning experience.</p>
<h3 id="not-libreware">Not libreware</h3>
<p>This refers to <a href="https://en.wikipedia.org/wiki/Proprietary_software">proprietary
software</a> that
implements spaced repetition, some of which are even guilty for
removing the spaced repetition feature that their users paid for. I
had a paid subscription with <a href="https://quizlet.com/">quizlet</a> only to
find out that they removed the spaced repetition feature I had already
paid &amp; was using, rendering my then workflow obsolete.</p>
<p>Do not depend on software you don&rsquo;t own for your work. <strong>You don&rsquo;t
&ldquo;own&rdquo; proprietary software, despite paying for it.</strong></p>
<blockquote>
<p>You should strive to use only <a href="https://en.wikipedia.org/wiki/Free_software">libreware</a> for your workflow.</p>
</blockquote>
<h3 id="lack-of-customization">Lack of customization</h3>
<p>Good software should fit your workflow like a glove, to do that it has
to give <em>a lot of</em> room for user customization. Trivial changes such
as color-scheme changes to more advanced feature customization like
adding your own custom card types and changing the spaced repetition
algorithm should be simple and easy to make. For example, a med
student would use a longer time interval for his algorithm than, let&rsquo;s
say, someone trying to expand their Japanese vocabulary.</p>
<p>Since we already established the need for our ideal software to be
<em>libreware</em>, making changes to the core components would be trivial.
But it should be added that customization to fit different needs &amp;
learning styles should be a primary goal when designing a SRS.</p>
<h3 id="flashcards-are-an-inferior-learning-method.">Flashcards are an inferior learning method.</h3>
<p>Flashcards are quite trivial to make, prototypical spaced repetition
methods utilized physical flashcards. Today&rsquo;s computers allows us for
more sophisticated &lsquo;review&rsquo; methods, <em>such as using user input</em>.</p>
<p>Utilizing user input to assess the effectiveness of a review is
preferable to simply revealing an answer and asking whether it was
known or not. This approach ensures not only the comprehension of the
answer but also the accurate spelling of it. Moreover, it leads to
more efficient retention compared to simply displaying the answer
without any active engagement from the user.</p>
<p>Ideally with <a href="https://git.thanosapollo.org/gnosis">Gnosis</a> I would
also like to implement
<a href="https://en.wikipedia.org/wiki/Multiple_choice">MCQ</a> type to simulate
the <a href="https://en.wikipedia.org/wiki/Usmle">USMLEs</a> exams which I will
<em>hopefully</em> soon be undertaking. <em>This will make it possible to simulate any other MCQ exam</em></p>
<h3 id="no-self-rating">No self-rating</h3>
<p>It is recommended that users do not self-rate their answers. The
review process should involve a binary assessment of success or
failure, where users either recall the answer correctly or not. This
success/failure rating will be used to determine the next interval for
the specific note, optimizing the spaced repetition system for
effective learning.</p>
<h3 id="collaboration">Collaboration</h3>
<p>Most spaced repetition software relies on databases for storage, but
the downside is that databases are not easily readable or editable by
humans, hindering sharing and collaboration.</p>
<p>To address this limitation, I intend to incorporate exporting
capabilities on gnosis. This feature would enable users to export a
deck of notes in a user-friendly format, which can then be easily
shared and collaborated on using tools like
<a href="https://en.wikipedia.org/wiki/Git">git</a> repositories.</p>
<p>This collaborative approach would allow us to work together, share,
and create valuable learning materials that can be used and modified
by everyone involved.</p>
<h3 id="syncing-between-devices">Syncing between devices</h3>
<p>Anki makes syncing between devices a breeze! But it gets terrible slow
if you are syncing a new device when you have a lot of material in
your account, plus you depend on Anki&rsquo;s servers for it to work.</p>
<p>Since on gnosis I will be using
<a href="https://en.wikipedia.org/wiki/Sqlite">sqlite</a> as my database
implementation, I would just be using git to keep my database in sync
between different devices.</p>
<h2 id="gnosis">Gnosis</h2>
<p>You can find gnosis on my git server
<a href="https://git.thanosapollo.org/gnosis">here</a>, <em>read the about section for installation instructions</em>.</p>
<p>It&rsquo;s still not even in alpha version yet, but it has the fundamental
functionality there already for you to test. Feel free to email me if
you have any questions or requests for gnosis.</p>]]></content:encoded>
    </item>
    <item>
      <title>Switching To Gentoo Linux</title>
      <link>https://thanosapollo.org/posts/gentoo-beginning/</link>
      <pubDate>Sun, 12 Nov 2023 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gentoo-beginning/</guid>
      <description>The end-game of my Linux journey has begun | Switching to Gentoo, the beginning.</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve leveled up to become a Gentoo user, the most elite nerd species
in GNU/Linux Land. All my devices have been transformed into Gentoo
machines, and needless to say, I&rsquo;m ecstatic about it.</p>
<p><em>Disclaimer: This post contains a healthy amount of sarcasm, just in
case you didn&rsquo;t catch on.</em></p>
<figure>
    <img loading="lazy" src="/images/setup-07-11-2023.jpg"
         alt="Gentoo Desktop and Thinkpad Setup" width="450"/> 
</figure>

<h2 id="about">About</h2>
<p>I&rsquo;ve been an <a href="https://archlinux.org">Arch Linux</a> user for a while now,
Arch Linux was the first distro I&rsquo;ve ever installed on hardware. It
treated me well over the past year, but after trying out gentoo on a virtual
machine I think I&rsquo;ve found my <code>$HOME</code>. Now I&rsquo;m running
<a href="https://gentoo.org">Gentoo</a> on all of my devices for the past 2+ weeks.</p>
<h2 id="what-did-you-enjoy-so-much-about-gentoo">What did you enjoy so much about Gentoo?</h2>
<h3 id="gentoo-handbook">Gentoo Handbook</h3>
<p><a href="https://wiki.gentoo.org/wiki/Handbook:Main_Page">The Gentoo Handbook</a>, I
can&rsquo;t really stress this enough, the Gentoo Handbook, is
<strong><em>extensively</em></strong> documented with every detail you might need,
<strong><em>specifically</em></strong> for using Gentoo. The Arch Wiki is awesome, it
includes documentation for a wide range of programs, but it&rsquo;s a
generic documentation that feels more like a general &ldquo;Linux wiki&rdquo;
rather than specific for Arch Linux. Even the parts that are specific
to Arch Linux, such as the installation instructions, are <em>severely</em> lacking,
which leads to most of the Arch Linux users to rely on third party
guides even on how to install their OS.</p>
<p>No other Linux Distribution has a centralized &ldquo;book&rdquo; that takes you
&ldquo;by the hand&rdquo; from the installation process all the way to working
with native software tools that you&rsquo;ll interact with on a daily basis, that
can compare to the Gentoo Handbook.</p>
<h3 id="community">Community</h3>
<p>One thing that I advocate about choosing which software to use is:</p>
<blockquote>
<p>Use software projects that you wouldn&rsquo;t mind / would like contributing to</p>
</blockquote>
<p>Gentoo community is the most helpful one that I&rsquo;ve found so far,
specifically I&rsquo;ve had people on the <a href="https://wiki.gentoo.org/wiki/Project:GURU">GURU
Project</a>, <em>analogous to the
AUR</em> package software that I needed as well as help me on
contributing, which has been a rather pleasant &amp; chill experience.</p>
<blockquote>
<p>If a project has a &ldquo;toxic&rdquo; community that you don&rsquo;t want to interact
with, its a huge red-flag for me.</p>
</blockquote>
<h2 id="but-why-would-you-compile-everything-from-source">But&hellip; Why would you compile everything from source?</h2>
<blockquote>
<p><em>Because someone has too&hellip;</em></p>
</blockquote>
<p>Jokes aside, there are many advantages to compiling your system from
source rather than installing an already made binary that someone
else compiled, hoping that it is compiled the way you want.</p>
<blockquote>
<p><a href="https://yewtu.be/watch?v=8QcI43IwkVc">Mental Outlaw (Invidious)</a>
has made a nice video explaining some important details/reasons for
running Gentoo, as well as <a href="https://yewtu.be/watch?v=6JUD-ZYuLPA">10leej
(Invidious)</a>, if you want to learn more.</p>
</blockquote>
<h2 id="it-takes-way-too-much-time-install-nobody-has-time-for-that">It takes way too much time install, nobody has time for that!</h2>
<p>It doesn&rsquo;t really take that much more time from installing Arch Linux,
I&rsquo;ve installed Gentoo on my desktop (Ryzen 7 5800X) the first time, in
~2 hours, most of which I&rsquo;ve spend reading the handbook. For reference,
my compile times are as follows:</p>
<p><em>output of <code>genlop -t &lt;package&gt;</code></em></p>
<blockquote>
<p>sys-kernel/gentoo-kernel-6.1.57 merge time: 15 minutes and 40 seconds.
www-client/firefox-115.4.0 merge time: 15 minutes and 26 seconds.
app-editors/emacs-29.1-r1 merge time: 52 seconds.
x11-wm/qtile-0.22.1-r2 merge time: 6 seconds.</p>
</blockquote>
<p>The only time consuming compile times I&rsquo;ve seen were for firefox &amp;
linux kernel, both of which are just 30 min combined, you also have
the option to use -bin packages instead. With the exception of those 2
packages mentioned above, I haven&rsquo;t spend more than 2 minutes
compiling a package.</p>
<p>I&rsquo;ve first considered setting up <a href="https://www.distcc.org/">distcc</a> for
my ThinkPad x220, but eventually I decided to let firefox &amp;
gentoo-kernel compile while I&rsquo;m on the gym for my workout.</p>
<blockquote>
<p>Note: I&rsquo;ve only installed ~700 packages on ThinkPad, and ~900 on my
desktop, most of that difference is due to installing
qemu/virt-manager on my desktop &amp; random fonts. I&rsquo;m not using a DE,
if you are planning to use GNOME or KDE etc. you might have a
different experience than me in that regard, since many DE&rsquo;s are
quite large and take a lot of time to compile.</p>
</blockquote>
<h2 id="summary">Summary</h2>
<p>I&rsquo;ve been enjoying running Gentoo on all my devices for the past
weeks. One of the main advantages of Gentoo is the control it provides
for tailoring your system to your liking. This is bundled with one of the
best documentation, if not the best, available to learn everything you
need to know about using your Linux system.</p>
<p>The community is rather chill &amp; friendly that welcomes new
contributions and will help you with any issue you might have.</p>
<blockquote>
<p>If you are able to read and follow instructions on how to install &amp; use your
system, you will find Gentoo to be a simple, reliable Linux
Distribution, with a helpful community. If you want a &ldquo;just works&rdquo;
experience, stay away from Gentoo, it&rsquo;s a &ldquo;Nerd&rsquo;s Only Allowed&rdquo;
place.</p>
</blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Why we need more .org sites.</title>
      <link>https://thanosapollo.org/posts/more-org-sites/</link>
      <pubDate>Tue, 07 Nov 2023 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/more-org-sites/</guid>
      <description>Why change the site extension to .org from .com</description>
      <content:encoded><![CDATA[<p>Today&rsquo;s web needs more .org sites. I&rsquo;m changing this site&rsquo;s extension
to thanosapollo.org from .com.</p>
<h2 id="about">About</h2>
<p>I&rsquo;ve first registered this site using <code>thanosapollo.com</code>, <code>.com</code> is
the <em>default</em> when it comes to today&rsquo;s websites, roughly 50% of
websites use it and that&rsquo;s what most users are familiar with.</p>
<blockquote>
<p><code>.com</code> stands for commercial/for profit, although it&rsquo;s sometimes
also used by blogs and nonprofit sites to capture more visitors. On
the other hand, <code>.org</code> is associated with nonprofit organizations,
or that generally provide free information and resources.</p>
</blockquote>
<!--quoteend-->
<blockquote>
<p>The context of this post refers to <code>.org</code> not just as a top level
domain, but as a freely accessible FOSS site.</p>
</blockquote>
<h2 id="why-switch-to-.org-and-why-we-need-more-.org-sites">Why switch to .org and why we need more .org sites</h2>
<p>I&rsquo;m not planning to use this site for any kind of commercial/for
profit purpose, having a <code>.org</code> extension implies that this site purpose
is non-commercial. Even though it&rsquo;s less popular, I find that today&rsquo;s
web landscape needs more <code>.org</code> sites and less <code>.com</code>.</p>
<p>About ~10 years ago, <em>when I was 13 years old</em>, the web seemed to be a
sanctuary of freely available information. 10 years later, even
useless information is behind a javascript pay-wall or login portal.
The web&rsquo;s increased traffic has been followed with lesser valuable
content creation, with today&rsquo;s users being accustomed to using the
&lsquo;web&rsquo; only through mobile social media apps, making them tied to a
proprietary ecosystem where they don&rsquo;t even own their profiles on said
platforms, their webmaster does.</p>
<p>We need more sites that offer free information for all and less people
behind proprietary platforms. I hope in the future we have more people
actually owning the sites they share their content. They might make
blogs or whatever else they like, as long as less of them end up at
the mercy of big tech <code>.com</code> companies.</p>
<blockquote>
<p>Even if you are after creating only for-profit content, making your
business depend entirely on a 3rd party is not the brightest idea.</p>
</blockquote>
<h2 id="difficulties-of-changing-my-site-to-.org">Difficulties of changing my site to .org</h2>
<p>The only issue with changing my site&rsquo;s extension was updating my
project&rsquo;s git remotes &amp; package recipes as well email services to the
new domain name. Although this is more of an inconvenience rather
than an actual difficulty.</p>]]></content:encoded>
    </item>
    <item>
      <title>pcomplete-yay | Extensible completions for yay in eshell</title>
      <link>https://thanosapollo.org/posts/pcomplete-yay/</link>
      <pubDate>Fri, 13 Oct 2023 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/pcomplete-yay/</guid>
      <description>Extensible completions for yay in eshell [Emacs Package]</description>
      <content:encoded><![CDATA[<p>Eshell is my favorite shell, but it&rsquo;s not as polished or well
documented for daily tasks. One such example is using completions for
package managers, like yay, to install/remove packages.</p>
<h2 id="about">About</h2>
<p>I&rsquo;m using eshell more than any other shell lately, but it&rsquo;s lacking in
terms of completions when it comes to other shells.</p>
<p>I&rsquo;ve made this simple package to provide completions for installing &amp;
removing packages using <a href="https://github.com/Jguer/yay">yay</a>.</p>
<p>Eshell provides a seamless integration with the rest of the Emacs
ecosystem &amp; thanks to the integration it has with
<a href="https://codeberg.org/akib/emacs-eat">Eat</a> it has no issue with visual
commands as of now, that previously struggled with. All it&rsquo;s missing is
decent completion features, which I believe we will see more of soon.</p>
<h2 id="installation">Installation</h2>
<p>You can get <code>pcomplete-yay</code> by following the instructions on project&rsquo;s
<a href="https://git.thanosapollo.org/pcomplete-yay/about">git repo</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Setting Firefox to use emacs keybindings</title>
      <link>https://thanosapollo.org/posts/firefox-with-emacs-keybindings/</link>
      <pubDate>Wed, 11 Oct 2023 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/firefox-with-emacs-keybindings/</guid>
      <description>Setting up firefox with emacs keybindings, using vimium.</description>
      <content:encoded><![CDATA[<p>Returning to Firefox from Nyxt, while preserving the Emacs-style workflow and
keybindings.</p>
<h2 id="about">About</h2>
<p>I love Emacs, but it&rsquo;s definitely not a viable alternative to modern
browsers like firefox. The desire to have an &rsquo;emacs-like&rsquo; browser lead
me to use <a href="https://nyxt.atlas.engineer">Nyxt</a>.</p>
<p>Although nyxt is impressive, it has some rough edges and inherent
issues. Furthermore, several websites that utilize cloudflare fail to
function properly with nyxt, leading to an unending verification loop.</p>
<p>Presently, I have chosen to use Firefox with Emacs-like keybindings
through the
<a href="https://addons.mozilla.org/en-US/firefox/addon/vimium-ff">vimiun</a>
extension.</p>
<p><em>Here is a concise guide on replicating this setup.</em></p>
<h3 id="step-i-aboutconfig">Step I: about:config</h3>
<p>First visit <code>about:config</code>.</p>
<p>To enable Emacs keybindings while editing text in Firefox, make the
following changes:</p>
<ul>
<li>Set <code>ui.key.accelKey</code> to <code>18</code></li>
<li>Set <code>ui.key.chromeAccess</code> to <code>0</code></li>
<li>Set <code>devtools.editor.keymap</code> to <code>emacs</code></li>
</ul>
<h3 id="step-ii-gtk-key-theme">Step II: gtk-key-theme</h3>
<p>Now, adjust <code>.config/gtk-3.0/settings.ini</code>, make sure you&rsquo;ve added
<code>gtk-key-theme-name = Emacs</code> It should look something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[Settings]
</span></span><span style="display:flex;"><span>.....
</span></span><span style="display:flex;"><span>gtk-key-theme-name = Emacs
</span></span></code></pre></div><h3 id="step-iii-vimium">Step III: Vimium</h3>
<p>Install <a href="https://addons.mozilla.org/en-US/firefox/addon/vimium-ff">vimium</a>.</p>
<p>Go on Vimium&rsquo;s Options page to, <em>by clicking the addon</em>, and adjust
<code>Custom Key Mappings</code>, here&rsquo;s an example setup for Emacs.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>unmapAll # use emacs-style bindings only
</span></span><span style="display:flex;"><span>map &lt;c-n&gt; scrollDown
</span></span><span style="display:flex;"><span>map &lt;c-p&gt; scrollUp
</span></span><span style="display:flex;"><span>map &lt;c-b&gt; goBack
</span></span><span style="display:flex;"><span>map &lt;c-f&gt; goForward
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;. scrollToTop
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;, scrollToBottom
</span></span><span style="display:flex;"><span>map &lt;c-V&gt; scrollFullPageUp
</span></span><span style="display:flex;"><span>map &lt;c-v&gt; scrollFullPageDown
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-r&gt; reload
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;k removeTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-u&gt; copyCurrentUrl
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-l&gt; LinkHints.activateModeToCopyLinkUrl
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-o&gt; openCopiedUrlInCurrentTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-O&gt; openCopiedUrlInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-i&gt; enterInsertMode
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-f&gt; LinkHints.activateMode
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-F&gt; LinkHints.activateModeToOpenInNewForegroundTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;a-f&gt; LinkHints.activateModeWithQueue
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;f LinkHints.activateModeToOpenInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-d&gt; Vomnibar.activate
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-D&gt; Vomnibar.activateInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;b Vomnibar.activateTabSelection
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-b&gt; Vomnibar.activateBookmarks
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-B&gt; Vomnibar.activateBookmarksInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-@&gt; Marks.activateCreateMode
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-@&gt; Marks.activateGotoMode
</span></span><span style="display:flex;"><span>map &lt;c-s&gt; enterFindMode
</span></span><span style="display:flex;"><span>map &lt;c-S&gt; performFind
</span></span><span style="display:flex;"><span>map &lt;c-r&gt; performBackwardsFind
</span></span><span style="display:flex;"><span>map &lt;c-R&gt; performBackwardsFind
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;b previousTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;f nextTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;4 duplicateTab
</span></span><span style="display:flex;"><span>map &lt;c-g&gt;&lt;c-r&gt; restoreTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;5 moveTabToNewWindow
</span></span><span style="display:flex;"><span>map &lt;c-g&gt;&lt;c-p&gt; togglePinTab
</span></span><span style="display:flex;"><span>map &lt;a-B&gt; moveTabLeft
</span></span><span style="display:flex;"><span>map &lt;a-F&gt; moveTabRight
</span></span><span style="display:flex;"><span>map &lt;c-h&gt; showHelp
</span></span></code></pre></div><p>You can find a complete vimium configuration that I&rsquo;m using in my
<a href="https://git.thanosapollo.org/dotfiles/tree/vimium-options.json">dotfiles
repo</a></p>
<h2 id="related-content">Related content</h2>
<ul>
<li><a href="https://github.com/raamdev/vimium">Raamdev vimium emacs configuration</a></li>
<li><a href="https://github.com/bwachter/emacs-keybinding">emacs-keybinding addon</a> <em>I do not recommend using this addon</em></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Self hosting SearXNG in 2023</title>
      <link>https://thanosapollo.org/posts/starting-point-searxng/</link>
      <pubDate>Mon, 25 Sep 2023 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/starting-point-searxng/</guid>
      <description>My experience self hosting SearXNG, the best way to surf the net until now.</description>
      <content:encoded><![CDATA[<p>Hosting SearXNG has been the easiest one to setup thus far, it literally takes 5 minutes. It&rsquo;s benefits are more than just privacy, let&rsquo;s dive into it.</p>
<ul>
<li>You can find my SearXNG instance <a href="https://search.thanosapollo.com">here</a></li>
</ul>
<h2 id="about">About</h2>
<p>SearXNG is a meta search engine, <em>aggregates search results from various sources</em>. No search engine today provides adequate results, everything is filled with ads and sites that just optimize for SEO &amp; quantity over quality.</p>
<ul>
<li><em>Most of today&rsquo;s mainstream sites provide worse content than chat gpt 3.5.</em></li>
</ul>
<h3 id="what-issues-does-searxng-solve">What issues does SearXNG solve?</h3>
<p><strong>Finding Good Content &amp; Finding it FAST!</strong>
I don&rsquo;t like wasting my time, <em>unless it&rsquo;s about configuring emacs</em>, I just want to search for something and get the best results ASAP.</p>
<blockquote>
<p>But Thanos, what do you mean? It&rsquo;s a meta search engine, it&rsquo;s not as fast as something like google or duckduckgo</p>
</blockquote>
<p>Yes! Since SearXNG aggregates results from different sources, it&rsquo;s not as fast as using a single one of them alone. <em>But&hellip;</em> let&rsquo;s see a scenario that you want to search for a video, you&rsquo;d open your browser, then go to youtube.com <em>or odysee</em>, then search for your video query. If you were using SearXNG all you&rsquo;d have to do is just type <code>!yt</code> <em>VIDEO-QUERY</em>. Maybe you are looking for a book? just type <code>!aa book-title</code> on the saerch bar and you will get results from <a href="https://annas-archive.org">annas-archive.org</a></p>
<p>It&rsquo;s even more powerful for researching &lsquo;scientific&rsquo; topics. I can directly search pubmed for <code>nano-antibiotics in treatment of lung infection</code> by just writing <code>!pub</code> in front of the search query.</p>
<p>I&rsquo;m using <a href="https://nyxt.atlas.engineer/">Nyxt</a> as my browser, I had set different keybindings to search pubmed &amp; the archlinux wiki but using a meta search engine like SearXNG is even more powerful than that &amp; way easier to setup, <strong>offering ~70 search engines!</strong>.</p>
<h2 id="how-to-setup-searxng">How to setup SearXNG</h2>
<ul>
<li>I&rsquo;m using <a href="https://www.ionos.com">Ionos</a> to host my SearXNG instance, it offers unlimited bandwidth for just 1$/month, <em>the best deal that I&rsquo;ve found.</em></li>
<li>The best guide that I&rsquo;ve found on setting up SearXNG is at <a href="https://landchad.net/searxng">landchad.net</a> <em>by <a href="https://goshawk22.uk">goshawk22</a></em>, refer to this guide &amp; to the <a href="https://docs.searxng.org/">SearXNG docs</a> if you have any issues.</li>
</ul>
<h3 id="step-1-clone-the-repo-run-the-installation-script">Step 1: Clone the repo &amp; run the installation script</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ git clone https://github.com/searxng/searxng /usr/local/searxng/searxng-src
</span></span><span style="display:flex;"><span>$ cd /usr/local/searxng/searxng-src
</span></span><span style="display:flex;"><span>$ ./utils/searxng.sh install all
</span></span></code></pre></div><h3 id="step-2-configure-nginx">Step 2: Configure nginx</h3>
<p>Create a new file <code>/etc/nginx/sites-available/searxng.conf</code> and add the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>server {
</span></span><span style="display:flex;"><span>    # Listens on http
</span></span><span style="display:flex;"><span>    listen 80;
</span></span><span style="display:flex;"><span>    listen [::]:80;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    # Your server name
</span></span><span style="display:flex;"><span>    server_name searx. example.org ;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    # If you want to log user activity, comment these
</span></span><span style="display:flex;"><span>    access_log /dev/null;
</span></span><span style="display:flex;"><span>    error_log  /dev/null;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    # X-Frame-Options (XFO) header set to DENY
</span></span><span style="display:flex;"><span>    add_header X-Frame-Options &#34;DENY&#34;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    # HTTP Strict Transport Security (HSTS) header
</span></span><span style="display:flex;"><span>    add_header Strict-Transport-Security &#34;max-age=31536000; includeSubDomains&#34;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    # Content Security Policy (CSP)
</span></span><span style="display:flex;"><span>    add_header Content-Security-Policy &#34;default-src &#39;self&#39;;&#34;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    location / {
</span></span><span style="display:flex;"><span>        uwsgi_pass unix:///usr/local/searxng/run/socket;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        include uwsgi_params;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        uwsgi_param    HTTP_HOST             $host;
</span></span><span style="display:flex;"><span>        uwsgi_param    HTTP_CONNECTION       $http_connection;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        # see flaskfix.py
</span></span><span style="display:flex;"><span>        uwsgi_param    HTTP_X_SCHEME         $scheme;
</span></span><span style="display:flex;"><span>        uwsgi_param    HTTP_X_SCRIPT_NAME    /searxng;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        # see limiter.py
</span></span><span style="display:flex;"><span>        uwsgi_param    HTTP_X_REAL_IP        $remote_addr;
</span></span><span style="display:flex;"><span>        uwsgi_param    HTTP_X_FORWARDED_FOR  $proxy_add_x_forwarded_for;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ul>
<li>Create a symbolic link to enable this site.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ ln -s /etc/nginx/sites-available/searxng.conf /etc/nginx/sites-enabled/searxng.conf
</span></span></code></pre></div><ul>
<li>Now all you have to do is restart Nginx and SearXNG.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ systemctl restart nginx
</span></span><span style="display:flex;"><span>$ service uwsgi restart searxng
</span></span></code></pre></div><ul>
<li>Setting up <code>https</code> connection with certbot <em>optional</em></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ apt install python3-certbot-nginx <span style="color:#75715e"># install certbot</span>
</span></span><span style="display:flex;"><span>$ certbot --nginx
</span></span></code></pre></div><h3 id="step-3-configuring-your-instance">Step 3: Configuring your instance</h3>
<p>You will be playing around with those 2 paths:</p>
<p><code>/etc/searxng/settings.yml</code> &amp; <code>/usr/local/searxng</code></p>
<p>You can find the default configuration <a href="https://github.com/searxng/searxng/blob/master/searx/settings.yml">here</a>, although I recommend using the default settings as much as possible if you are just starting out.</p>
<p>Your theming configuration lies at <code>usr/local/searxng/searxng-src/searx/static/themes/simple</code> you can remove &amp; edit the default logos or do whatever fancy stuff you like there.</p>]]></content:encoded>
    </item>
    <item>
      <title>yeetube | Emacs Front-End for YouTube (blog)</title>
      <link>https://thanosapollo.org/posts/yeetube/</link>
      <pubDate>Wed, 20 Sep 2023 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/yeetube/</guid>
      <description>Creating a front-end to play YouTube videos with Emacs</description>
      <content:encoded><![CDATA[<p>To learn elisp I decided to work on a project that I&rsquo;ve felt was
missing on the GNU Emacs ecosystem, a direct front-end for YouTube.</p>
<p><strong>Update 2024-02-26</strong>: This is an old blog post from when I started working on this
project. Check out the <a href="/projects/yeetube/">Project&rsquo;s Page</a> for
up-to-date information.</p>
<blockquote>
<p>This package does not use any kind of an API, just parses html &amp;
json using regex.</p>
</blockquote>
<h2 id="motivation">Motivation</h2>
<p>I simple wanted to learn elisp, and decided to not watch any youtube
content unless it&rsquo;s inside emacs. This way I also saved a lot of time
that I&rsquo;d otherwise waste watching random youtube videos.</p>
<p>Watching youtube through <a href="https://youtube.com">youtube.com</a> is way too
distracting, the sites purpose is to keep you hooked with recommended
videos that do the bare minimum to keep you engaged. Not to mention
that the platform is basically proprietary spyware.</p>
<p>Despite that, many academics decide to upload their videos and even
lectures there, so other than entertainment it&rsquo;s a valuable learning
resource.</p>
<h2 id="installation-guide">Installation Guide</h2>
<p><a href="https://git.thanosapollo.org/yeetube">Project&rsquo;s repo</a></p>
<p>You can install yeetube via <a href="https://melpa.org/#/yeetube">MELPA</a></p>
<h3 id="straight.el">Straight.el</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(straight-use-package
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#39;</span>(yeetube :type git
</span></span><span style="display:flex;"><span>           :host <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>           :repo <span style="color:#e6db74">&#34;https://git.thanosapollo.org/yeetube&#34;</span>))
</span></span></code></pre></div><h3 id="manual">Manual</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ git clone https://git.thanosapollo.org/yeetube
</span></span></code></pre></div><p>Add this to your emacs configuration</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;/path/to/yeetube&#34;</span>)
</span></span><span style="display:flex;"><span>(load-file <span style="color:#e6db74">&#34;~/path/to/yeetube.el&#34;</span>)
</span></span></code></pre></div>]]></content:encoded>
    </item>
  </channel>
</rss>
