small tweaks to sfeed_curses page and links - www.codemadness.org - www.codemadness.org saait content files
 (HTM) git clone git://git.codemadness.org/www.codemadness.org
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit b8b1949da72e732d4b0ce18e4b12baf1a9ed9750
 (DIR) parent aa794d3b1909cb60c010583a2da9a3582cdc6b16
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Thu, 24 Jul 2025 11:10:01 +0200
       
       small tweaks to sfeed_curses page and links
       
       Diffstat:
         M config.cfg                          |       2 +-
         M output/atom.xml                     |       4 ++--
         M output/atom_content.xml             |      15 +++++++++------
         M output/atom_content_gopher.xml      |      15 +++++++++------
         M output/atom_gopher.xml              |       4 ++--
         M output/jsonfeed_content.json        |       2 +-
         M output/jsonfeed_content_gopher.json |       2 +-
         M output/phlog/sfeed_curses-ui        |       8 ++++----
         M output/rss_content.xml              |      11 +++++++----
         M output/rss_content_gopher.xml       |      11 +++++++----
         M output/sfeed_content.tsv            |       2 +-
         M output/sfeed_content_gopher.tsv     |       2 +-
         M output/sfeed_curses-ui.html         |      11 +++++++----
         M output/sfeed_curses-ui.md           |       6 +++---
         M output/sitemap.xml                  |       2 +-
         M pages/sfeed_curses-ui.cfg           |       2 +-
         M pages/sfeed_curses-ui.md            |       6 +++---
       
       17 files changed, 60 insertions(+), 45 deletions(-)
       ---
 (DIR) diff --git a/config.cfg b/config.cfg
       @@ -1,5 +1,5 @@
        # last updated the site.
       -siteupdated = 2025-05-16
       +siteupdated = 2025-07-24
        
        sitetitle = Codemadness
        siteurl = https://www.codemadness.org
 (DIR) diff --git a/output/atom.xml b/output/atom.xml
       @@ -2,7 +2,7 @@
        <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
                <title>Codemadness</title>
                <subtitle>blog with various projects and articles about computer-related things</subtitle>
       -        <updated>2025-05-16T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <link rel="alternate" type="text/html" href="https://www.codemadness.org" />
                <id>https://www.codemadness.org/atom.xml</id>
                <link rel="self" type="application/atom+xml" href="https://www.codemadness.org/atom.xml" />
       @@ -106,7 +106,7 @@
                <title>Sfeed_curses: a curses UI front-end for sfeed</title>
                <link rel="alternate" type="text/html" href="https://www.codemadness.org/sfeed_curses-ui.html" />
                <id>https://www.codemadness.org/sfeed_curses-ui.html</id>
       -        <updated>2022-05-08T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <published>2020-06-25T00:00:00Z</published>
                <author>
                        <name>Hiltjo</name>
 (DIR) diff --git a/output/atom_content.xml b/output/atom_content.xml
       @@ -2,7 +2,7 @@
        <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
                <title>Codemadness</title>
                <subtitle>blog with various projects and articles about computer-related things</subtitle>
       -        <updated>2025-05-16T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <link rel="alternate" type="text/html" href="https://www.codemadness.org" />
                <id>https://www.codemadness.org/atom_content.xml</id>
                <link rel="self" type="application/atom+xml" href="https://www.codemadness.org/atom_content.xml" />
       @@ -1028,7 +1028,7 @@ run
                <title>Sfeed_curses: a curses UI front-end for sfeed</title>
                <link rel="alternate" type="text/html" href="https://www.codemadness.org/sfeed_curses-ui.html" />
                <id>https://www.codemadness.org/sfeed_curses-ui.html</id>
       -        <updated>2022-05-08T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <published>2020-06-25T00:00:00Z</published>
                <author>
                        <name>Hiltjo</name>
       @@ -1036,7 +1036,7 @@ run
                </author>
                <summary>Sfeed_curses is a curses UI front-end for the sfeed RSS/Atom parser</summary>
                <content type="html"><![CDATA[<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>
       -        <p><strong>Last modification on </strong> <time>2022-05-08</time></p>
       +        <p><strong>Last modification on </strong> <time>2025-07-24</time></p>
                <p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.
        It is now part of sfeed.</p>
        <p>It shows the TAB-separated feed items in a graphical command-line UI.  The
       @@ -1048,9 +1048,12 @@ integrated in the interface itself.</p>
        <ul>
        <li>Relatively few LOC, about 2.5K lines of C.</li>
        <li>Few dependencies: a C compiler and a curses library (typically ncurses).
       -It also requires a terminal (emulator) supporting UTF-8.</li>
       +It also requires a terminal (emulator) which supports UTF-8.
       +<ul>
       +<li>xterm-compatible shim <a href="https://git.codemadness.org/sfeed/file/minicurses.h.html">minicurses.h</a></li>
       +</ul>
       +</li>
        <li>Easy to customize by modifying the small source-code and shellscripts.</li>
       -<li>Quite fast.</li>
        <li>Plumb support: open the URL or an enclosure URL directly with any program.</li>
        <li>Pipe support: pipe the selected Tab-Separated Value line to a program for
        scripting purposes. Like viewing the content in any way you like.</li>
       @@ -1088,7 +1091,7 @@ This line is in the exact same format as described in the sfeed(5) man page.</p>
        <p>The pipe program can be changed by setting the environment variable
        $SFEED_PIPER.</p>
        <p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>
       -<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a> shellscript which uses
       +<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed/file/sfeed_content.html">sfeed_content</a> shellscript which uses
        the <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted
        plain-text to the user $PAGER (or "less").</p>
        <p>Of course the script can be easily changed to use a different browser or
 (DIR) diff --git a/output/atom_content_gopher.xml b/output/atom_content_gopher.xml
       @@ -2,7 +2,7 @@
        <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
                <title>Codemadness</title>
                <subtitle>blog with various projects and articles about computer-related things</subtitle>
       -        <updated>2025-05-16T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <link rel="alternate" type="text/gopher" href="gopher://codemadness.org" />
                <id>gopher://codemadness.org/0/atom_content_gopher.xml</id>
                <link rel="self" type="application/atom+xml" href="gopher://codemadness.org/0/atom_content_gopher.xml" />
       @@ -1028,7 +1028,7 @@ run
                <title>Sfeed_curses: a curses UI front-end for sfeed</title>
                <link rel="alternate" type="text/gopher" href="gopher://codemadness.org/1/phlog/sfeed_curses" />
                <id>gopher://codemadness.org/1/phlog/sfeed_curses</id>
       -        <updated>2022-05-08T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <published>2020-06-25T00:00:00Z</published>
                <author>
                        <name>Hiltjo</name>
       @@ -1036,7 +1036,7 @@ run
                </author>
                <summary>Sfeed_curses is a curses UI front-end for the sfeed RSS/Atom parser</summary>
                <content type="html"><![CDATA[<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>
       -        <p><strong>Last modification on </strong> <time>2022-05-08</time></p>
       +        <p><strong>Last modification on </strong> <time>2025-07-24</time></p>
                <p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.
        It is now part of sfeed.</p>
        <p>It shows the TAB-separated feed items in a graphical command-line UI.  The
       @@ -1048,9 +1048,12 @@ integrated in the interface itself.</p>
        <ul>
        <li>Relatively few LOC, about 2.5K lines of C.</li>
        <li>Few dependencies: a C compiler and a curses library (typically ncurses).
       -It also requires a terminal (emulator) supporting UTF-8.</li>
       +It also requires a terminal (emulator) which supports UTF-8.
       +<ul>
       +<li>xterm-compatible shim <a href="https://git.codemadness.org/sfeed/file/minicurses.h.html">minicurses.h</a></li>
       +</ul>
       +</li>
        <li>Easy to customize by modifying the small source-code and shellscripts.</li>
       -<li>Quite fast.</li>
        <li>Plumb support: open the URL or an enclosure URL directly with any program.</li>
        <li>Pipe support: pipe the selected Tab-Separated Value line to a program for
        scripting purposes. Like viewing the content in any way you like.</li>
       @@ -1088,7 +1091,7 @@ This line is in the exact same format as described in the sfeed(5) man page.</p>
        <p>The pipe program can be changed by setting the environment variable
        $SFEED_PIPER.</p>
        <p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>
       -<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a> shellscript which uses
       +<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed/file/sfeed_content.html">sfeed_content</a> shellscript which uses
        the <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted
        plain-text to the user $PAGER (or "less").</p>
        <p>Of course the script can be easily changed to use a different browser or
 (DIR) diff --git a/output/atom_gopher.xml b/output/atom_gopher.xml
       @@ -2,7 +2,7 @@
        <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
                <title>Codemadness</title>
                <subtitle>blog with various projects and articles about computer-related things</subtitle>
       -        <updated>2025-05-16T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <link rel="alternate" type="text/gopher" href="gopher://codemadness.org" />
                <id>gopher://codemadness.org/0/atom_gopher.xml</id>
                <link rel="self" type="application/atom+xml" href="gopher://codemadness.org/0/atom_gopher.xml" />
       @@ -106,7 +106,7 @@
                <title>Sfeed_curses: a curses UI front-end for sfeed</title>
                <link rel="alternate" type="text/gopher" href="gopher://codemadness.org/1/phlog/sfeed_curses" />
                <id>gopher://codemadness.org/1/phlog/sfeed_curses</id>
       -        <updated>2022-05-08T00:00:00Z</updated>
       +        <updated>2025-07-24T00:00:00Z</updated>
                <published>2020-06-25T00:00:00Z</published>
                <author>
                        <name>Hiltjo</name>
 (DIR) diff --git a/output/jsonfeed_content.json b/output/jsonfeed_content.json
       @@ -72,7 +72,7 @@
                "title": "Sfeed_curses: a curses UI front-end for sfeed",
                "url": "https://www.codemadness.org/sfeed_curses-ui.html",
                "authors": [{"name": "Hiltjo"}],
       -        "content_html": "<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2022-05-08</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href=\"sfeed.html\">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href=\"http://www.mutt.org/\">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) supporting UTF-8.</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Quite fast.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_screenshot.png\" alt=\"Screenshot showing what the UI looks\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href=\"https://portland.freedesktop.org/doc/xdg-open.html\">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\" alt=\"Screenshot showing the output of the pipe content script\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>The above screenshot shows the included <a href=\"https://git.codemadness.org/sfeed_curses/file/sfeed_content.html\">sfeed_content</a> shellscript which uses\nthe <a href=\"https://invisible-island.net/lynx/\">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or \"less\").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href=\"https://www.dillo.org/\">dillo</a></li>\n<li><a href=\"http://www.jikos.cz/~mikulas/links/\">links</a></li>\n<li><a href=\"http://w3m.sourceforge.net/\">w3m</a></li>\n<li><a href=\"https://git.codemadness.org/webdump/file/README.html\">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href=\"https://templeos.org/\">TempleOS</a>-like color-theme on the right a\n<a href=\"https://newsboat.org/\">newsboat</a>-like colorscheme.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\" alt=\"Screenshot showing a custom colorscheme\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\" alt=\"Screenshot showing the horizontal layout\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href=\"https://git.codemadness.org/sfeed/\">https://git.codemadness.org/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/git/sfeed\">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href=\"https://codemadness.org/releases/sfeed/\">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/releases/sfeed\">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>"
       +        "content_html": "<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2025-07-24</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href=\"sfeed.html\">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href=\"http://www.mutt.org/\">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) which supports UTF-8.\n<ul>\n<li>xterm-compatible shim <a href=\"https://git.codemadness.org/sfeed/file/minicurses.h.html\">minicurses.h</a></li>\n</ul>\n</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_screenshot.png\" alt=\"Screenshot showing what the UI looks\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href=\"https://portland.freedesktop.org/doc/xdg-open.html\">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\" alt=\"Screenshot showing the output of the pipe content script\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>The above screenshot shows the included <a href=\"https://git.codemadness.org/sfeed/file/sfeed_content.html\">sfeed_content</a> shellscript which uses\nthe <a href=\"https://invisible-island.net/lynx/\">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or \"less\").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href=\"https://www.dillo.org/\">dillo</a></li>\n<li><a href=\"http://www.jikos.cz/~mikulas/links/\">links</a></li>\n<li><a href=\"http://w3m.sourceforge.net/\">w3m</a></li>\n<li><a href=\"https://git.codemadness.org/webdump/file/README.html\">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href=\"https://templeos.org/\">TempleOS</a>-like color-theme on the right a\n<a href=\"https://newsboat.org/\">newsboat</a>-like colorscheme.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\" alt=\"Screenshot showing a custom colorscheme\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\" alt=\"Screenshot showing the horizontal layout\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href=\"https://git.codemadness.org/sfeed/\">https://git.codemadness.org/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/git/sfeed\">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href=\"https://codemadness.org/releases/sfeed/\">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/releases/sfeed\">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>"
        },
        {
                "id": "https://www.codemadness.org/hurl.html",
 (DIR) diff --git a/output/jsonfeed_content_gopher.json b/output/jsonfeed_content_gopher.json
       @@ -72,7 +72,7 @@
                "title": "Sfeed_curses: a curses UI front-end for sfeed",
                "url": "gopher://codemadness.org/1/phlog/sfeed_curses",
                "authors": [{"name": "Hiltjo"}],
       -        "content_html": "<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2022-05-08</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href=\"sfeed.html\">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href=\"http://www.mutt.org/\">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) supporting UTF-8.</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Quite fast.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_screenshot.png\" alt=\"Screenshot showing what the UI looks\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href=\"https://portland.freedesktop.org/doc/xdg-open.html\">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\" alt=\"Screenshot showing the output of the pipe content script\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>The above screenshot shows the included <a href=\"https://git.codemadness.org/sfeed_curses/file/sfeed_content.html\">sfeed_content</a> shellscript which uses\nthe <a href=\"https://invisible-island.net/lynx/\">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or \"less\").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href=\"https://www.dillo.org/\">dillo</a></li>\n<li><a href=\"http://www.jikos.cz/~mikulas/links/\">links</a></li>\n<li><a href=\"http://w3m.sourceforge.net/\">w3m</a></li>\n<li><a href=\"https://git.codemadness.org/webdump/file/README.html\">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href=\"https://templeos.org/\">TempleOS</a>-like color-theme on the right a\n<a href=\"https://newsboat.org/\">newsboat</a>-like colorscheme.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\" alt=\"Screenshot showing a custom colorscheme\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\" alt=\"Screenshot showing the horizontal layout\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href=\"https://git.codemadness.org/sfeed/\">https://git.codemadness.org/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/git/sfeed\">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href=\"https://codemadness.org/releases/sfeed/\">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/releases/sfeed\">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>"
       +        "content_html": "<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2025-07-24</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href=\"sfeed.html\">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href=\"http://www.mutt.org/\">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) which supports UTF-8.\n<ul>\n<li>xterm-compatible shim <a href=\"https://git.codemadness.org/sfeed/file/minicurses.h.html\">minicurses.h</a></li>\n</ul>\n</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_screenshot.png\" alt=\"Screenshot showing what the UI looks\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href=\"https://portland.freedesktop.org/doc/xdg-open.html\">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_pipe_screenshot.png\" alt=\"Screenshot showing the output of the pipe content script\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>The above screenshot shows the included <a href=\"https://git.codemadness.org/sfeed/file/sfeed_content.html\">sfeed_content</a> shellscript which uses\nthe <a href=\"https://invisible-island.net/lynx/\">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or \"less\").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href=\"https://www.dillo.org/\">dillo</a></li>\n<li><a href=\"http://www.jikos.cz/~mikulas/links/\">links</a></li>\n<li><a href=\"http://w3m.sourceforge.net/\">w3m</a></li>\n<li><a href=\"https://git.codemadness.org/webdump/file/README.html\">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href=\"https://templeos.org/\">TempleOS</a>-like color-theme on the right a\n<a href=\"https://newsboat.org/\">newsboat</a>-like colorscheme.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_theme_screenshot.png\" alt=\"Screenshot showing a custom colorscheme\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\"><img src=\"downloads/screenshots/sfeed_curses_horizontal_screenshot.png\" alt=\"Screenshot showing the horizontal layout\" width=\"480\" height=\"270\" loading=\"lazy\" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href=\"https://git.codemadness.org/sfeed/\">https://git.codemadness.org/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/git/sfeed\">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href=\"https://codemadness.org/releases/sfeed/\">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href=\"gopher://codemadness.org/1/releases/sfeed\">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>"
        },
        {
                "id": "gopher://codemadness.org/1/phlog/hurl",
 (DIR) diff --git a/output/phlog/sfeed_curses-ui b/output/phlog/sfeed_curses-ui
       @@ -3,7 +3,7 @@ i                codemadness.org        70
        i                codemadness.org        70
        i# Sfeed_curses: a curses UI front-end for sfeed                codemadness.org        70
        i                codemadness.org        70
       -iLast modification on 2022-05-08                codemadness.org        70
       +iLast modification on 2025-07-24                codemadness.org        70
        i                codemadness.org        70
        1sfeed_curses is a curses UI front-end for »sfeed«.        /phlog/sfeed        codemadness.org        70
        iIt is now part of sfeed.                codemadness.org        70
       @@ -19,9 +19,9 @@ i## Features                codemadness.org        70
        i                codemadness.org        70
        i* Relatively few LOC, about 2.5K lines of C.                codemadness.org        70
        i* Few dependencies: a C compiler and a curses library (typically ncurses).                codemadness.org        70
       -i  It also requires a terminal (emulator) supporting UTF-8.                codemadness.org        70
       +i  It also requires a terminal (emulator) which supports UTF-8.                codemadness.org        70
       +1  * xterm-compatible shim »minicurses.h«        /git/sfeed/file/minicurses.h.gph        codemadness.org        70
        i* Easy to customize by modifying the small source-code and shellscripts.                codemadness.org        70
       -i* Quite fast.                codemadness.org        70
        i* Plumb support: open the URL or an enclosure URL directly with any program.                codemadness.org        70
        i* Pipe support: pipe the selected Tab-Separated Value line to a program for                codemadness.org        70
        i  scripting purposes. Like viewing the content in any way you like.                codemadness.org        70
       @@ -68,7 +68,7 @@ i$SFEED_PIPER.                codemadness.org        70
        i                codemadness.org        70
        IScreenshot showing the output of the pipe content script        /downloads/screenshots/sfeed_curses_pipe_screenshot.png        codemadness.org        70
        i                codemadness.org        70
       -1The above screenshot shows the included »sfeed_content« shellscript which uses        /git/sfeed_curses/file/sfeed_content.gph        codemadness.org        70
       +1The above screenshot shows the included »sfeed_content« shellscript which uses        /git/sfeed/file/sfeed_content.gph        codemadness.org        70
        hthe »lynx text-browser« to convert HTML to plain-text.  It pipes the formatted        URL:https://invisible-island.net/lynx/        codemadness.org        70
        iplain-text to the user $PAGER (or "less").                codemadness.org        70
        i                codemadness.org        70
 (DIR) diff --git a/output/rss_content.xml b/output/rss_content.xml
       @@ -991,7 +991,7 @@ run
                <dc:date>2020-06-25T00:00:00Z</dc:date>
                <author>Hiltjo</author>
                <description><![CDATA[<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>
       -        <p><strong>Last modification on </strong> <time>2022-05-08</time></p>
       +        <p><strong>Last modification on </strong> <time>2025-07-24</time></p>
                <p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.
        It is now part of sfeed.</p>
        <p>It shows the TAB-separated feed items in a graphical command-line UI.  The
       @@ -1003,9 +1003,12 @@ integrated in the interface itself.</p>
        <ul>
        <li>Relatively few LOC, about 2.5K lines of C.</li>
        <li>Few dependencies: a C compiler and a curses library (typically ncurses).
       -It also requires a terminal (emulator) supporting UTF-8.</li>
       +It also requires a terminal (emulator) which supports UTF-8.
       +<ul>
       +<li>xterm-compatible shim <a href="https://git.codemadness.org/sfeed/file/minicurses.h.html">minicurses.h</a></li>
       +</ul>
       +</li>
        <li>Easy to customize by modifying the small source-code and shellscripts.</li>
       -<li>Quite fast.</li>
        <li>Plumb support: open the URL or an enclosure URL directly with any program.</li>
        <li>Pipe support: pipe the selected Tab-Separated Value line to a program for
        scripting purposes. Like viewing the content in any way you like.</li>
       @@ -1043,7 +1046,7 @@ This line is in the exact same format as described in the sfeed(5) man page.</p>
        <p>The pipe program can be changed by setting the environment variable
        $SFEED_PIPER.</p>
        <p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>
       -<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a> shellscript which uses
       +<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed/file/sfeed_content.html">sfeed_content</a> shellscript which uses
        the <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted
        plain-text to the user $PAGER (or "less").</p>
        <p>Of course the script can be easily changed to use a different browser or
 (DIR) diff --git a/output/rss_content_gopher.xml b/output/rss_content_gopher.xml
       @@ -991,7 +991,7 @@ run
                <dc:date>2020-06-25T00:00:00Z</dc:date>
                <author>Hiltjo</author>
                <description><![CDATA[<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>
       -        <p><strong>Last modification on </strong> <time>2022-05-08</time></p>
       +        <p><strong>Last modification on </strong> <time>2025-07-24</time></p>
                <p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.
        It is now part of sfeed.</p>
        <p>It shows the TAB-separated feed items in a graphical command-line UI.  The
       @@ -1003,9 +1003,12 @@ integrated in the interface itself.</p>
        <ul>
        <li>Relatively few LOC, about 2.5K lines of C.</li>
        <li>Few dependencies: a C compiler and a curses library (typically ncurses).
       -It also requires a terminal (emulator) supporting UTF-8.</li>
       +It also requires a terminal (emulator) which supports UTF-8.
       +<ul>
       +<li>xterm-compatible shim <a href="https://git.codemadness.org/sfeed/file/minicurses.h.html">minicurses.h</a></li>
       +</ul>
       +</li>
        <li>Easy to customize by modifying the small source-code and shellscripts.</li>
       -<li>Quite fast.</li>
        <li>Plumb support: open the URL or an enclosure URL directly with any program.</li>
        <li>Pipe support: pipe the selected Tab-Separated Value line to a program for
        scripting purposes. Like viewing the content in any way you like.</li>
       @@ -1043,7 +1046,7 @@ This line is in the exact same format as described in the sfeed(5) man page.</p>
        <p>The pipe program can be changed by setting the environment variable
        $SFEED_PIPER.</p>
        <p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>
       -<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a> shellscript which uses
       +<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed/file/sfeed_content.html">sfeed_content</a> shellscript which uses
        the <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted
        plain-text to the user $PAGER (or "less").</p>
        <p>Of course the script can be easily changed to use a different browser or
 (DIR) diff --git a/output/sfeed_content.tsv b/output/sfeed_content.tsv
       @@ -6,7 +6,7 @@
        1656633600        A simple TODO application        https://www.codemadness.org/todo-application.html        <h1>A simple TODO application</h1>\n\t<p><strong>Last modification on </strong> <time>2022-07-01</time></p>\n\t<p>This article describes a TODO application or workflow.</p>\n<h2>Workflow</h2>\n<p>It works like this:</p>\n<ul>\n<li>Open any text editor.</li>\n<li>Edit the text.</li>\n<li>Save it in a file (probably named "TODO").</li>\n<li>Feel happy about it.</li>\n</ul>\n<h2>The text format</h2>\n<p>The text format I use is this:</p>\n<pre><code>[indendations]&lt;symbol&gt;&lt;SPACE&gt;&lt;item text&gt;&lt;NEWLINE&gt;\n</code></pre>\n<p>Most of the time an item is just one line.\nThis format is just a general guideline to keep the items somewhat structured.</p>\n<h2>Symbols</h2>\n<p>Items are prefixed with a symbol.</p>\n<ul>\n<li>- is an item which is planned to be done at some point.</li>\n<li>x is an item which is done.</li>\n<li>? is an item which I'm not (yet) sure about. It can also be an idea.</li>\n</ul>\n<p>I use an indendation with a TAB before an item to indicate item dependencies.\nThe items can be nested.</p>\n<p>For the prioritization I put the most important items and sections from the top\nto the bottom. These can be reshuffled as you wish of course.</p>\n<p>To delete an item you remove the line. To archive an item you keep the line.</p>\n<h2>Sections</h2>\n<p>A section is a line which has no symbol. This is like a header to group items.</p>\n<h2>Example</h2>\n<pre><code>Checklist for releasing project 0.1:\n- Test project with different compilers and check for warnings.\n- Documentation:\n\t- Proofread and make sure it matches all program behaviour.\n\t- Run mandoc -Tlint on the man pages.\n\t? Copy useful examples from the README file to the man page?\n- Run testsuite and check for failures before release.\n\n\nproject 0.2:\n? Investigate if feature mentioned by some user is worth adding.\n</code></pre>\n<h1>Example: secure remote cloud-encrypted edit session(tm)</h1>\n<pre><code>ssh -t host 'ed TODO'\n</code></pre>\n<h1>Example: multi-user secure remote cloud-encrypted edit session(tm)</h1>\n<pre><code>ssh host\ntmux or tmux a\ned TODO\n</code></pre>\n<h1>Example: version-controlled multi-user secure remote cloud-encrypted edit session(tm)</h1>\n<pre><code>ssh host\ntmux or tmux a\ned TODO\ngit add TODO\ngit commit -m 'TODO: update'\n</code></pre>\n<h2>Pros</h2>\n<ul>\n<li>When you open the TODO file the most important items are at the top.</li>\n<li>The items are easy to read and modify with any text editor.</li>\n<li>It is easy to extend the format and use with other text tools.</li>\n<li>The format is portable: it works on sticky-notes on your CRT monitor too!</li>\n<li>No monthly online subscription needed and full NO-money-back guarantee.</li>\n</ul>\n<h2>Cons</h2>\n<ul>\n<li>Complex lists with interconnected dependencies might not work, maybe.</li>\n<li>It's assumed there is one person maintaining the TODO file. Merging items\nfrom multiple people at the same time in this workflow is not recommended.</li>\n<li>It is too simple: noone will be impressed by it.</li>\n</ul>\n<p>I hope this is inspirational or something,</p>        html        https://www.codemadness.org/todo-application.html        Hiltjo                
        1647993600        2FA TOTP without crappy authenticator apps        https://www.codemadness.org/totp.html        <h1>2FA TOTP without crappy authenticator apps</h1>\n\t<p><strong>Last modification on </strong> <time>2022-10-29</time></p>\n\t<p>This describes how to use 2FA without using crappy authenticator "apps" or a\nmobile device.</p>\n<h2>Install</h2>\n<p>On OpenBSD:</p>\n<pre><code>pkg_add oath-toolkit zbar\n</code></pre>\n<p>On Void Linux:</p>\n<pre><code>xbps-install oath-toolkit zbar\n</code></pre>\n<p>There is probably a package for your operating system.</p>\n<ul>\n<li>oath-toolkit is used to generate the digits based on the secret key.</li>\n<li>zbar is used to scan the QR barcode text from the image.</li>\n</ul>\n<h2>Steps</h2>\n<p>Save the QR code image from the authenticator app, website to an image file.\nScan the QR code text from the image:</p>\n<pre><code>zbarimg image.png\n</code></pre>\n<p>An example QR code:</p>\n<p><img src="downloads/2fa/qr.png" alt="QR code example" /></p>\n<p>The output is typically something like:</p>\n<pre><code>QR-Code:otpauth://totp/Example:someuser@codemadness.org?secret=SECRETKEY&amp;issuer=Codemadness\n</code></pre>\n<p>You only need to scan this QR-code for the secret key once.\nMake sure to store the secret key in a private safe place and don't show it to\nanyone else.</p>\n<p>Using the secret key the following command outputs a 6-digit code by default.\nIn this example we also assume the key is base32-encoded.\nThere can be other parameters and options, this is documented in the Yubico URI\nstring format reference below.</p>\n<p>Command:</p>\n<pre><code>oathtool --totp -b SOMEKEY\n</code></pre>\n<ul>\n<li>The --totp option uses the time-variant TOTP mode, by default it uses HMAC SHA1.</li>\n<li>The -b option uses base32 encoding of KEY instead of hex.</li>\n</ul>\n<p>Tip: you can create a script that automatically puts the digits in the\nclipboard, for example:</p>\n<pre><code>oathtool --totp -b SOMEKEY | xclip\n</code></pre>\n<h2>References</h2>\n<ul>\n<li><a href="https://linux.die.net/man/1/zbarimg">zbarimg(1) man page</a></li>\n<li><a href="https://www.nongnu.org/oath-toolkit/man-oathtool.html">oathtool(1) man page</a></li>\n<li><a href="https://datatracker.ietf.org/doc/html/rfc6238">RFC6238 - TOTP: Time-Based One-Time Password Algorithm</a></li>\n<li><a href="https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html">Yubico.com - otpauth URI string format</a></li>\n</ul>        html        https://www.codemadness.org/totp.html        Hiltjo                
        1634947200        Setup an OpenBSD RISCV64 VM in QEMU        https://www.codemadness.org/openbsd-riscv64-vm.html        <h1>Setup an OpenBSD RISCV64 VM in QEMU</h1>\n\t<p><strong>Last modification on </strong> <time>2021-10-26</time></p>\n\t<p>This describes how to setup an OpenBSD RISCV64 VM in QEMU.</p>\n<p>The shellscript below does the following:</p>\n<ul>\n<li>Set up the disk image (raw format).</li>\n<li>Patch the disk image with the OpenBSD miniroot file for the installation.</li>\n<li>Downloads the opensbi and u-boot firmware files for qemu.</li>\n<li>Run the VM with the supported settings.</li>\n</ul>\n<p>The script is tested on the host GNU/Void Linux and OpenBSD-current.</p>\n<p><strong>IMPORTANT!: The signature and checksum for the miniroot, u-boot and opensbi\nfiles are not verified. If the host is OpenBSD make sure to instead install the\npackages (pkg_add u-boot-riscv64 opensbi) and adjust the firmware path for the\nqemu -bios and -kernel options. </strong></p>\n<h2>Shellscript</h2>\n<pre><code>#!/bin/sh\n# mirror list: https://www.openbsd.org/ftp.html\nmirror="https://ftp.bit.nl/pub/OpenBSD/"\nrelease="7.0"\nminirootname="miniroot70.img"\n\nminiroot() {\n\ttest -f "${minirootname}" &amp;&amp; return # download once\n\n\turl="${mirror}/${release}/riscv64/${minirootname}"\n\tcurl -o "${minirootname}" "${url}"\n}\n\ncreaterootdisk() {\n\ttest -f disk.raw &amp;&amp; return # create once\n\tqemu-img create disk.raw 10G # create 10 GB disk\n\tdd conv=notrunc if=${minirootname} of=disk.raw # write miniroot to disk\n}\n\nopensbi() {\n\tf="opensbi.tgz"\n\ttest -f "${f}" &amp;&amp; return # download and extract once.\n\n\turl="${mirror}/${release}/packages/amd64/opensbi-0.9p0.tgz"\n\tcurl -o "${f}" "${url}"\n\n\ttar -xzf "${f}" share/opensbi/generic/fw_jump.bin\n}\n\nuboot() {\n\tf="uboot.tgz"\n\ttest -f "${f}" &amp;&amp; return # download and extract once.\n\n\turl="${mirror}/${release}/packages/amd64/u-boot-riscv64-2021.07p0.tgz"\n\tcurl -o "${f}" "${url}"\n\n\ttar -xzf "${f}" share/u-boot/qemu-riscv64_smode/u-boot.bin\n}\n\nsetup() {\n\tminiroot\n\tcreaterootdisk\n\topensbi\n\tuboot\n}\n\nrun() {\n\tqemu-system-riscv64 \\\n\t\t-machine virt \\\n\t\t-nographic \\\n\t\t-m 2048M \\\n\t\t-smp 2 \\\n\t\t-bios share/opensbi/generic/fw_jump.bin \\\n\t\t-kernel share/u-boot/qemu-riscv64_smode/u-boot.bin \\\n\t\t-drive file=disk.raw,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 \\\n\t\t-netdev user,id=net0,ipv6=off -device virtio-net-device,netdev=net0\n}\n\nsetup\nrun\n</code></pre>        html        https://www.codemadness.org/openbsd-riscv64-vm.html        Hiltjo                
       -1593043200        Sfeed_curses: a curses UI front-end for sfeed        https://www.codemadness.org/sfeed_curses-ui.html        <h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2022-05-08</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href="http://www.mutt.org/">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) supporting UTF-8.</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Quite fast.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href="downloads/screenshots/sfeed_curses_screenshot.png"><img src="downloads/screenshots/sfeed_curses_screenshot.png" alt="Screenshot showing what the UI looks" width="480" height="270" loading="lazy" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href="https://portland.freedesktop.org/doc/xdg-open.html">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>\n<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a> shellscript which uses\nthe <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or "less").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href="https://www.dillo.org/">dillo</a></li>\n<li><a href="http://www.jikos.cz/~mikulas/links/">links</a></li>\n<li><a href="http://w3m.sourceforge.net/">w3m</a></li>\n<li><a href="https://git.codemadness.org/webdump/file/README.html">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href="https://templeos.org/">TempleOS</a>-like color-theme on the right a\n<a href="https://newsboat.org/">newsboat</a>-like colorscheme.</p>\n<p><a href="downloads/screenshots/sfeed_curses_theme_screenshot.png"><img src="downloads/screenshots/sfeed_curses_theme_screenshot.png" alt="Screenshot showing a custom colorscheme" width="480" height="270" loading="lazy" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href="downloads/screenshots/sfeed_curses_horizontal_screenshot.png"><img src="downloads/screenshots/sfeed_curses_horizontal_screenshot.png" alt="Screenshot showing the horizontal layout" width="480" height="270" loading="lazy" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/sfeed/">https://git.codemadness.org/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/git/sfeed">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/sfeed/">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/sfeed">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>        html        https://www.codemadness.org/sfeed_curses-ui.html        Hiltjo                
       +1593043200        Sfeed_curses: a curses UI front-end for sfeed        https://www.codemadness.org/sfeed_curses-ui.html        <h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2025-07-24</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href="http://www.mutt.org/">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) which supports UTF-8.\n<ul>\n<li>xterm-compatible shim <a href="https://git.codemadness.org/sfeed/file/minicurses.h.html">minicurses.h</a></li>\n</ul>\n</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href="downloads/screenshots/sfeed_curses_screenshot.png"><img src="downloads/screenshots/sfeed_curses_screenshot.png" alt="Screenshot showing what the UI looks" width="480" height="270" loading="lazy" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href="https://portland.freedesktop.org/doc/xdg-open.html">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>\n<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed/file/sfeed_content.html">sfeed_content</a> shellscript which uses\nthe <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or "less").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href="https://www.dillo.org/">dillo</a></li>\n<li><a href="http://www.jikos.cz/~mikulas/links/">links</a></li>\n<li><a href="http://w3m.sourceforge.net/">w3m</a></li>\n<li><a href="https://git.codemadness.org/webdump/file/README.html">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href="https://templeos.org/">TempleOS</a>-like color-theme on the right a\n<a href="https://newsboat.org/">newsboat</a>-like colorscheme.</p>\n<p><a href="downloads/screenshots/sfeed_curses_theme_screenshot.png"><img src="downloads/screenshots/sfeed_curses_theme_screenshot.png" alt="Screenshot showing a custom colorscheme" width="480" height="270" loading="lazy" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href="downloads/screenshots/sfeed_curses_horizontal_screenshot.png"><img src="downloads/screenshots/sfeed_curses_horizontal_screenshot.png" alt="Screenshot showing the horizontal layout" width="480" height="270" loading="lazy" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/sfeed/">https://git.codemadness.org/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/git/sfeed">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/sfeed/">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/sfeed">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>        html        https://www.codemadness.org/sfeed_curses-ui.html        Hiltjo                
        1573344000        hurl: HTTP, HTTPS and Gopher file grabber        https://www.codemadness.org/hurl.html        <h1>hurl: HTTP, HTTPS and Gopher file grabber</h1>\n\t<p><strong>Last modification on </strong> <time>2020-07-20</time></p>\n\t<p>hurl is a relatively simple HTTP, HTTPS and Gopher client/file grabber.</p>\n<h2>Why?</h2>\n<p>Sometimes (or most of the time?) you just want to fetch a file via the HTTP,\nHTTPS or Gopher protocol.</p>\n<p>The focus of this tool is only this.</p>\n<h2>Features</h2>\n<ul>\n<li>Uses OpenBSD pledge(2) and unveil(2). Allow no filesystem access (writes to\nstdout).</li>\n<li>Impose time-out and maximum size limits.</li>\n<li>Use well-defined exitcodes for reliable scripting (curl sucks at this).</li>\n<li>Send as little information as possible (no User-Agent etc by default).</li>\n</ul>\n<h2>Anti-features</h2>\n<ul>\n<li>No HTTP byte range support.</li>\n<li>No HTTP User-Agent.</li>\n<li>No HTTP If-Modified-Since/If-* support.</li>\n<li>No HTTP auth support.</li>\n<li>No HTTP/2+ support.</li>\n<li>No HTTP keep-alive.</li>\n<li>No HTTP chunked-encoding support.</li>\n<li>No HTTP redirect support.</li>\n<li>No (GZIP) compression support.</li>\n<li>No cookie-jar or cookie parsing support.</li>\n<li>No Gopher text handling (".\\r\\n").</li>\n<li>... etc...</li>\n</ul>\n<h2>Dependencies</h2>\n<ul>\n<li>C compiler (C99).</li>\n<li>libc + some BSD functions like err() and strlcat().</li>\n<li>LibreSSL(-portable)</li>\n<li>libtls (part of LibreSSL).</li>\n</ul>\n<h2>Optional dependencies</h2>\n<ul>\n<li>POSIX make(1) (for Makefile).</li>\n<li>mandoc for documentation: <a href="https://mdocml.bsd.lv/">https://mdocml.bsd.lv/</a></li>\n</ul>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/hurl\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/hurl/">https://git.codemadness.org/hurl/</a></li>\n<li><a href="gopher://codemadness.org/1/git/hurl">gopher://codemadness.org/1/git/hurl</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/hurl/">https://codemadness.org/releases/hurl/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/hurl">gopher://codemadness.org/1/releases/hurl</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>\n<h2>Examples</h2>\n<p>Fetch the Atom feed from this site using a maximum filesize limit of 1MB and\na time-out limit of 15 seconds:</p>\n<pre><code>hurl -m 1048576 -t 15 "https://codemadness.org/atom.xml"\n</code></pre>\n<p>There is an -H option to add custom headers. This way some of the anti-features\nlisted above are supported. For example some CDNs like Cloudflare are known to\nblock empty or certain User-Agents.</p>\n<p>User-Agent:</p>\n<pre><code>hurl -H 'User-Agent: some browser' 'https://codemadness.org/atom.xml'\n</code></pre>\n<p>HTTP Basic Auth (base64-encoded username:password):</p>\n<pre><code>hurl -H 'Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=' \\\n\t'https://codemadness.org/atom.xml'\n</code></pre>\n<p>GZIP (this assumes the served response Content-Type is gzip):</p>\n<pre><code>hurl -H 'Accept-Encoding: gzip' 'https://somesite/' | gzip -d\n</code></pre>        html        https://www.codemadness.org/hurl.html        Hiltjo                
        1570924800        json2tsv: a JSON to TSV converter        https://www.codemadness.org/json2tsv.html        <h1>json2tsv: a JSON to TSV converter</h1>\n\t<p><strong>Last modification on </strong> <time>2021-09-25</time></p>\n\t<p>Convert JSON to TSV or separated output.</p>\n<p>json2tsv reads JSON data from stdin.  It outputs each JSON type to a TAB-\nSeparated Value format per line by default.</p>\n<h2>TAB-Separated Value format</h2>\n<p>The output format per line is:</p>\n<pre><code>nodename&lt;TAB&gt;type&lt;TAB&gt;value&lt;LF&gt;\n</code></pre>\n<p>Control-characters such as a newline, TAB and backslash (\\n, \\t and \\) are\nescaped in the nodename and value fields.  Other control-characters are\nremoved.</p>\n<p>The type field is a single byte and can be:</p>\n<ul>\n<li>a for array</li>\n<li>b for bool</li>\n<li>n for number</li>\n<li>o for object</li>\n<li>s for string</li>\n<li>? for null</li>\n</ul>\n<p>Filtering on the first field "nodename" is easy using awk for example.</p>\n<h2>Features</h2>\n<ul>\n<li>Accepts all <strong>valid</strong> JSON.</li>\n<li>Designed to work well with existing UNIX programs like awk and grep.</li>\n<li>Straightforward and not much lines of code: about 475 lines of C.</li>\n<li>Few dependencies: C compiler (C99), libc.</li>\n<li>No need to learn a new (meta-)language for processing data.</li>\n<li>The parser supports code point decoding and UTF-16 surrogates to UTF-8.</li>\n<li>It does not output control-characters to the terminal for security reasons by\ndefault (but it has a -r option if needed).</li>\n<li>On OpenBSD it supports <a href="https://man.openbsd.org/pledge">pledge(2)</a> for syscall restriction:\npledge("stdio", NULL).</li>\n<li>Supports setting a different field separator and record separator with the -F\nand -R option.</li>\n</ul>\n<h2>Cons</h2>\n<ul>\n<li>For the tool there is additional overhead by processing and filtering data\nfrom stdin after parsing.</li>\n<li>The parser does not do complete validation on numbers.</li>\n<li>The parser accepts some bad input such as invalid UTF-8\n(see <a href="https://tools.ietf.org/html/rfc8259#section-8.1">RFC8259 - 8.1. Character Encoding</a>).\njson2tsv reads from stdin and does not do assumptions about a "closed\necosystem" as described in the RFC.</li>\n<li>The parser accepts some bad JSON input and "extensions"\n(see <a href="https://tools.ietf.org/html/rfc8259#section-9">RFC8259 - 9. Parsers</a>).</li>\n<li>Encoded NUL bytes (\\u0000) in strings are ignored.\n(see <a href="https://tools.ietf.org/html/rfc8259#section-9">RFC8259 - 9. Parsers</a>).\n"An implementation may set limits on the length and character contents of\nstrings."</li>\n<li>The parser is not the fastest possible JSON parser (but also not the\nslowest).  For example: for ease of use, at the cost of performance all\nstrings are decoded, even though they may be unused.</li>\n</ul>\n<h2>Why Yet Another JSON parser?</h2>\n<p>I wanted a tool that makes parsing JSON easier and work well from the shell,\nsimilar to <a href="https://stedolan.github.io/jq/">jq</a>.</p>\n<p>sed and grep often work well enough for matching some value using some regex\npattern, but it is not good enough to parse JSON correctly or to extract all\ninformation: just like parsing HTML/XML using some regex is not good (enough)\nor a good idea :P.</p>\n<p>I didn't want to learn a new specific <a href="https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions">meta-language</a> which jq has and wanted\nsomething simpler.</p>\n<p>While it is more efficient to embed this query language for data aggregation,\nit is also less simple. In my opinion it is simpler to separate this and use\npattern-processing by awk or an other filtering/aggregating program.</p>\n<p>For the parser, there are many JSON parsers out there, like the efficient\n<a href="https://github.com/zserge/jsmn">jsmn parser</a>, however a few parser behaviours I want to have are:</p>\n<ul>\n<li>jsmn buffers data as tokens, which is very efficient, but also a bit\nannoying as an API as it requires another layer of code to interpret the\ntokens.</li>\n<li>jsmn does not handle decoding strings by default. Which is very efficient\nif you don't need parts of the data though.</li>\n<li>jsmn does not keep context of nested structures by default, so may require\nwriting custom utility functions for nested data.</li>\n</ul>\n<p>This is why I went for a parser design that uses a single callback per "node"\ntype and keeps track of the current nested structure in a single array and\nemits that.</p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/json2tsv\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/json2tsv/">https://git.codemadness.org/json2tsv/</a></li>\n<li><a href="gopher://codemadness.org/1/git/json2tsv">gopher://codemadness.org/1/git/json2tsv</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/json2tsv/">https://codemadness.org/releases/json2tsv/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/json2tsv">gopher://codemadness.org/1/releases/json2tsv</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>\n<h2>Examples</h2>\n<p>An usage example to parse posts of the JSON API of <a href="https://www.reddit.com/">reddit.com</a> and format them\nto a plain-text list using awk:</p>\n<pre><code>#!/bin/sh\ncurl -s -H 'User-Agent:' 'https://old.reddit.com/.json?raw_json=1&amp;limit=100' | \\\njson2tsv | \\\nawk -F '\\t' '\nfunction show() {\n\tif (length(o["title"]) == 0)\n\t\treturn;\n\tprint n ". " o["title"] " by " o["author"] " in r/" o["subreddit"];\n\tprint o["url"];\n\tprint "";\n}\n$1 == ".data.children[].data" {\n\tshow();\n\tn++;\n\tdelete o;\n}\n$1 ~ /^\\.data\\.children\\[\\]\\.data\\.[a-zA-Z0-9_]*$/ {\n\to[substr($1, 23)] = $3;\n}\nEND {\n\tshow();\n}'\n</code></pre>\n<h2>References</h2>\n<ul>\n<li>Sites:\n<ul>\n<li><a href="http://seriot.ch/parsing_json.php">seriot.ch - Parsing JSON is a Minefield</a></li>\n<li><a href="https://github.com/nst/JSONTestSuite">A comprehensive test suite for RFC 8259 compliant JSON parsers</a></li>\n<li><a href="https://json.org/">json.org</a></li>\n</ul>\n</li>\n<li>Current standard:\n<ul>\n<li><a href="https://tools.ietf.org/html/rfc8259">RFC8259 - The JavaScript Object Notation (JSON) Data Interchange Format</a></li>\n<li><a href="https://www.ecma-international.org/publications/standards/Ecma-404.htm">Standard ECMA-404 - The JSON Data Interchange Syntax (2nd edition (December 2017)</a></li>\n</ul>\n</li>\n<li>Historic standards:\n<ul>\n<li><a href="https://tools.ietf.org/html/rfc7159">RFC7159 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete)</a></li>\n<li><a href="https://tools.ietf.org/html/rfc7158">RFC7158 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete)</a></li>\n<li><a href="https://tools.ietf.org/html/rfc4627">RFC4627 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete, original)</a></li>\n</ul>\n</li>\n</ul>        html        https://www.codemadness.org/json2tsv.html        Hiltjo                
        1556064000        OpenBSD: setup a local auto-installation server        https://www.codemadness.org/openbsd-autoinstall.html        <h1>OpenBSD: setup a local auto-installation server</h1>\n\t<p><strong>Last modification on </strong> <time>2020-04-30</time></p>\n\t<p>This guide describes how to setup a local mirror and installation/upgrade\nserver that requires little or no input interaction.</p>\n<h2>Setup a local HTTP mirror</h2>\n<p>The HTTP mirror will be used to fetch the base sets and (optional) custom sets.\nIn this guide we will assume <strong>192.168.0.2</strong> is the local installation server\nand mirror, the CPU architecture is amd64 and the OpenBSD release version is\n6.5.  We will store the files in the directory with the structure:</p>\n<pre><code>http://192.168.0.2/pub/OpenBSD/6.5/amd64/\n</code></pre>\n<p>Create the www serve directory and fetch all sets and install files\n(if needed to save space *.iso and install65.fs can be skipped):</p>\n<pre><code>$ cd /var/www/htdocs\n$ mkdir -p pub/OpenBSD/6.5/amd64/\n$ cd pub/OpenBSD/6.5/amd64/\n$ ftp 'ftp://ftp.nluug.nl/pub/OpenBSD/6.5/amd64/*'\n</code></pre>\n<p>Verify signature and check some checksums:</p>\n<pre><code>$ signify -C -p /etc/signify/openbsd-65-base.pub -x SHA256.sig\n</code></pre>\n<p>Setup <a href="https://man.openbsd.org/httpd.8">httpd(8)</a> for simple file serving:</p>\n<pre><code># $FAVORITE_EDITOR /etc/httpd.conf\n</code></pre>\n<p>A minimal example config for <a href="https://man.openbsd.org/httpd.conf.5">httpd.conf(5)</a>:</p>\n<pre><code>server "*" {\n\tlisten on * port 80\n}\n</code></pre>\n<p>The default www root directory is: /var/www/htdocs/</p>\n<p>Enable the httpd daemon to start by default and start it now:</p>\n<pre><code># rcctl enable httpd\n# rcctl start httpd\n</code></pre>\n<h2>Creating an installation response/answer file</h2>\n<p>The installer supports loading responses to the installation/upgrade questions\nfrom a simple text file. We can do a regular installation and copy the answers\nfrom the saved file to make an automated version of it.</p>\n<p>Do a test installation, at the end of the installation or upgrade when asked the\nquestion:</p>\n<pre><code>Exit to (S)hell, (H)alt or (R)eboot?\n</code></pre>\n<p>Type S to go to the shell. Find the response file for an installation and copy\nit to some USB stick or write down the response answers:</p>\n<pre><code>cp /tmp/i/install.resp /mnt/usbstick/\n</code></pre>\n<p>A response file could be for example:</p>\n<pre><code>System hostname = testvm\nWhich network interface do you wish to configure = em0\nIPv4 address for em0 = dhcp\nIPv6 address for em0 = none\nWhich network interface do you wish to configure = done\nPassword for root account = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.\nPassword for user testuser = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.\nStart sshd(8) by default = no\nDo you expect to run the X Window System = no\nSetup a user = testuser\nFull name for user testuser = testuser\nWhat timezone are you in = Europe/Amsterdam\nWhich disk is the root disk = wd0\nUse (W)hole disk MBR, whole disk (G)PT, (O)penBSD area or (E)dit = OpenBSD\nUse (A)uto layout, (E)dit auto layout, or create (C)ustom layout = a\nLocation of sets = http\nHTTP proxy URL = none\nHTTP Server = 192.168.0.2\nServer directory = pub/OpenBSD/6.5/amd64\nUnable to connect using https. Use http instead = yes\nLocation of sets = http\nSet name(s) = done\nLocation of sets = done\nExit to (S)hell, (H)alt or (R)eboot = R\n</code></pre>\n<p>Get custom encrypted password for response file:</p>\n<pre><code>$ printf '%s' 'yourpassword' | encrypt\n</code></pre>\n<h2>Changing the RAMDISK kernel disk image</h2>\n<p><a href="https://man.openbsd.org/rdsetroot.8">rdsetroot(8)</a> is publicly exposed now in base since 6.5. Before 6.5 it is\navailable in the /usr/src/ tree as elfrdsetroot, see also the <a href="https://man.openbsd.org/rd.4">rd(4)</a> man page.</p>\n<pre><code>$ mkdir auto\n$ cd auto\n$ cp pubdir/bsd.rd .\n$ rdsetroot -x bsd.rd disk.fs\n# vnconfig vnd0 disk.fs\n# mkdir mount\n# mount /dev/vnd0a mount\n</code></pre>\n<p>Copy the response file (install.resp) to: mount/auto_install.conf\n(installation) <strong>or</strong> mount/auto_upgrade.conf (upgrade), but not both. In this\nguide we will do an auto-installation.</p>\n<p>Unmount, detach and patch RAMDISK:</p>\n<pre><code># umount mount\n# vnconfig -u vnd0\n$ rdsetroot bsd.rd disk.fs\n</code></pre>\n<p>To test copy bsd.rd to the root of some testmachine like /bsd.test.rd then\n(re)boot and type:</p>\n<pre><code>boot /bsd.test.rd\n</code></pre>\n<p>In the future (6.5+) it will be possible to copy to a file named "/bsd.upgrade"\nin the root of a current system and automatically load the kernel:\n<a href="https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/stand/boot/boot.c?rev=1.46&amp;content-type=text/x-cvsweb-markup">See the script bsd.upgrade in CVS.</a>\nOf course this is possible with PXE boot or some custom USB/ISO also.\nAs explained in the <a href="https://man.openbsd.org/autoinstall.8">autoinstall(8)</a> man page: create either an\nauto_upgrade.conf <strong>or</strong> an auto_install.conf, but not both.</p>\n<h2>Create bootable miniroot</h2>\n<p>In this example the miniroot will boot the custom kernel, but fetch all the\nsets from the local network.</p>\n<p>We will base our miniroot of the official version: miniroot65.fs.</p>\n<p>We will create a 16MB miniroot to boot from (in this guide it is assumed the\noriginal miniroot is about 4MB and the modified kernel image fits in the new\nallocated space):</p>\n<pre><code>$ dd if=/dev/zero of=new.fs bs=512 count=32768\n</code></pre>\n<p>Copy first part of the original image to the new disk (no truncation):</p>\n<pre><code>$ dd conv=notrunc if=miniroot65.fs of=new.fs\n# vnconfig vnd0 new.fs\n</code></pre>\n<p>Expand disk OpenBSD boundaries:</p>\n<pre><code># disklabel -E vnd0\n&gt; b\nStarting sector: [1024]\nSize ('*' for entire disk): [8576] *\n&gt; r\nTotal free sectors: 1168.\n&gt; c a\nPartition a is currently 8576 sectors in size, and can have a maximum\nsize of 9744 sectors.\nsize: [8576] *\n&gt; w\n&gt; q\n</code></pre>\n<p>or:</p>\n<pre><code># printf 'b\\n\\n*\\nc a\\n*\\nw\\n' | disklabel -E vnd0\n</code></pre>\n<p>Grow filesystem and check it and mark as clean:</p>\n<pre><code># growfs -y /dev/vnd0a\n# fsck -y /dev/vnd0a\n</code></pre>\n<p>Mount filesystem:</p>\n<pre><code># mount /dev/vnd0a mount/\n</code></pre>\n<p>The kernel on the miniroot is GZIP compressed. Compress our modified bsd.rd and\noverwrite the original kernel:</p>\n<pre><code># gzip -c9n bsd.rd &gt; mount/bsd\n</code></pre>\n<p>Or to save space (+- 500KB) by stripping debug symbols, taken from bsd.gz target\n<a href="https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/distrib/amd64/iso/Makefile">in this Makefile</a>.</p>\n<pre><code>$ cp bsd.rd bsd.strip\n$ strip bsd.strip\n$ strip -R .comment -R .SUNW_ctf bsd.strip\n$ gzip -c9n bsd.strip &gt; bsd.gz\n$ cp bsd.gz mount/bsd\n</code></pre>\n<p>Now unmount and detach:</p>\n<pre><code># umount mount/\n# vnconfig -u vnd0\n</code></pre>\n<p>Now you can <a href="https://man.openbsd.org/dd.1">dd(1)</a> the image new.fs to your bootable (USB) medium.</p>\n<h2>Adding custom sets (optional)</h2>\n<p>For patching <a href="https://man.openbsd.org/rc.firsttime.8">/etc/rc.firsttime</a> and other system files it is useful to use a\ncustomized installation set like siteVERSION.tgz, for example: site65.tgz.  The\nsets can even be specified per host/MAC address like\nsiteVERSION-$(hostname -s).tgz so for example: site65-testvm.tgz</p>\n<p>When the installer checks the base sets of the mirror it looks for a file\nindex.txt.  To add custom sets the site entries have to be added.</p>\n<p>For example:</p>\n<pre><code>-rw-r--r--  1 1001  0    4538975 Oct 11 13:58:26 2018 site65-testvm.tgz\n</code></pre>\n<p>The filesize, permissions etc do not matter and are not checked by the\ninstaller.  Only the filename is matched by a regular expression.</p>\n<h2>Sign custom site* tarball sets (optional)</h2>\n<p>If you have custom sets without creating a signed custom release you will be\nprompted for the messages:</p>\n<pre><code>checksum test failed\n</code></pre>\n<p>and:</p>\n<pre><code>unverified sets: continue without verification\n</code></pre>\n<p>OpenBSD uses the program <a href="https://man.openbsd.org/signify.1">signify(1)</a> to cryptographically sign and\nverify filesets.</p>\n<p>To create a custom public/private keypair (ofcourse make sure to store the\nprivate key privately):</p>\n<pre><code>$ signify -G -n -c "Custom 6.5 install" -p custom-65-base.pub -s custom-65-base.sec\n</code></pre>\n<p>Create new checksum file with filelist of the current directory (except SHA256*\nfiles):</p>\n<pre><code>$ printf '%s\\n' * | grep -v SHA256 | xargs sha256 &gt; SHA256\n</code></pre>\n<p>Sign SHA256 and store as SHA256.sig, embed signature:</p>\n<pre><code>$ signify -S -e -s /privatedir/custom-65-base.sec -m SHA256 -x SHA256.sig\n</code></pre>\n<p>Verify the created signature and data is correct:</p>\n<pre><code>$ signify -C -p /somelocation/custom-65-base.pub -x SHA256.sig\n</code></pre>\n<p>Copy <strong>only</strong> the <strong>public</strong> key to the RAMDISK:</p>\n<pre><code>$ cp custom-65-base.pub mount/etc/signify/custom-65-base.pub\n</code></pre>\n<p>Now we have to patch the install.sub file to check our public key.  If you know\na better way without having to patch this script, please let me know.</p>\n<p>Change the variable PUB_KEY in the shellscript mount/install.sub from:</p>\n<pre><code>PUB_KEY=/etc/signify/openbsd-${VERSION}-base.pub\n</code></pre>\n<p>To:</p>\n<pre><code>PUB_KEY=/etc/signify/custom-${VERSION}-base.pub\n</code></pre>\n<p>And for upgrades from:</p>\n<pre><code>$UPGRADE_BSDRD &amp;&amp;\n\tPUB_KEY=/mnt/etc/signify/openbsd-$((VERSION + 1))-base.pub\n</code></pre>\n<p>To:</p>\n<pre><code>$UPGRADE_BSDRD &amp;&amp;\n\tPUB_KEY=/mnt/etc/signify/custom-$((VERSION + 1))-base.pub\n</code></pre>\n<h2>Ideas</h2>\n<ul>\n<li>Patch <a href="https://man.openbsd.org/rc.firsttime.8">rc.firsttime(8)</a>: and run syspatch, add ports, setup xenodm etc.</li>\n<li>Custom partitioning scheme, see <a href="https://man.openbsd.org/autoinstall.8">autoinstall(8)</a> "URL to autopartitioning\ntemplate for disklabel = url".</li>\n<li>Setup <a href="https://man.openbsd.org/pxeboot.8">pxeboot(8)</a> to boot and install over the network using\n<a href="https://man.openbsd.org/dhcpd.8">dhcpd(8)</a> and\n<a href="https://man.openbsd.org/tftpd.8">tftpd(8)</a> then not even some USB stick is required.</li>\n</ul>\n<h2>References</h2>\n<ul>\n<li>Main OpenBSD installation and upgrade shellscript:\n<a href="https://cvsweb.openbsd.org/src/distrib/miniroot/install.sub">/usr/src/distrib/miniroot/install.sub</a></li>\n</ul>        html        https://www.codemadness.org/openbsd-autoinstall.html        Hiltjo                
 (DIR) diff --git a/output/sfeed_content_gopher.tsv b/output/sfeed_content_gopher.tsv
       @@ -6,7 +6,7 @@
        1656633600        A simple TODO application        gopher://codemadness.org/1/phlog/todo        <h1>A simple TODO application</h1>\n\t<p><strong>Last modification on </strong> <time>2022-07-01</time></p>\n\t<p>This article describes a TODO application or workflow.</p>\n<h2>Workflow</h2>\n<p>It works like this:</p>\n<ul>\n<li>Open any text editor.</li>\n<li>Edit the text.</li>\n<li>Save it in a file (probably named "TODO").</li>\n<li>Feel happy about it.</li>\n</ul>\n<h2>The text format</h2>\n<p>The text format I use is this:</p>\n<pre><code>[indendations]&lt;symbol&gt;&lt;SPACE&gt;&lt;item text&gt;&lt;NEWLINE&gt;\n</code></pre>\n<p>Most of the time an item is just one line.\nThis format is just a general guideline to keep the items somewhat structured.</p>\n<h2>Symbols</h2>\n<p>Items are prefixed with a symbol.</p>\n<ul>\n<li>- is an item which is planned to be done at some point.</li>\n<li>x is an item which is done.</li>\n<li>? is an item which I'm not (yet) sure about. It can also be an idea.</li>\n</ul>\n<p>I use an indendation with a TAB before an item to indicate item dependencies.\nThe items can be nested.</p>\n<p>For the prioritization I put the most important items and sections from the top\nto the bottom. These can be reshuffled as you wish of course.</p>\n<p>To delete an item you remove the line. To archive an item you keep the line.</p>\n<h2>Sections</h2>\n<p>A section is a line which has no symbol. This is like a header to group items.</p>\n<h2>Example</h2>\n<pre><code>Checklist for releasing project 0.1:\n- Test project with different compilers and check for warnings.\n- Documentation:\n\t- Proofread and make sure it matches all program behaviour.\n\t- Run mandoc -Tlint on the man pages.\n\t? Copy useful examples from the README file to the man page?\n- Run testsuite and check for failures before release.\n\n\nproject 0.2:\n? Investigate if feature mentioned by some user is worth adding.\n</code></pre>\n<h1>Example: secure remote cloud-encrypted edit session(tm)</h1>\n<pre><code>ssh -t host 'ed TODO'\n</code></pre>\n<h1>Example: multi-user secure remote cloud-encrypted edit session(tm)</h1>\n<pre><code>ssh host\ntmux or tmux a\ned TODO\n</code></pre>\n<h1>Example: version-controlled multi-user secure remote cloud-encrypted edit session(tm)</h1>\n<pre><code>ssh host\ntmux or tmux a\ned TODO\ngit add TODO\ngit commit -m 'TODO: update'\n</code></pre>\n<h2>Pros</h2>\n<ul>\n<li>When you open the TODO file the most important items are at the top.</li>\n<li>The items are easy to read and modify with any text editor.</li>\n<li>It is easy to extend the format and use with other text tools.</li>\n<li>The format is portable: it works on sticky-notes on your CRT monitor too!</li>\n<li>No monthly online subscription needed and full NO-money-back guarantee.</li>\n</ul>\n<h2>Cons</h2>\n<ul>\n<li>Complex lists with interconnected dependencies might not work, maybe.</li>\n<li>It's assumed there is one person maintaining the TODO file. Merging items\nfrom multiple people at the same time in this workflow is not recommended.</li>\n<li>It is too simple: noone will be impressed by it.</li>\n</ul>\n<p>I hope this is inspirational or something,</p>        html        gopher://codemadness.org/1/phlog/todo        Hiltjo                
        1647993600        2FA TOTP without crappy authenticator apps        gopher://codemadness.org/1/phlog/totp        <h1>2FA TOTP without crappy authenticator apps</h1>\n\t<p><strong>Last modification on </strong> <time>2022-10-29</time></p>\n\t<p>This describes how to use 2FA without using crappy authenticator "apps" or a\nmobile device.</p>\n<h2>Install</h2>\n<p>On OpenBSD:</p>\n<pre><code>pkg_add oath-toolkit zbar\n</code></pre>\n<p>On Void Linux:</p>\n<pre><code>xbps-install oath-toolkit zbar\n</code></pre>\n<p>There is probably a package for your operating system.</p>\n<ul>\n<li>oath-toolkit is used to generate the digits based on the secret key.</li>\n<li>zbar is used to scan the QR barcode text from the image.</li>\n</ul>\n<h2>Steps</h2>\n<p>Save the QR code image from the authenticator app, website to an image file.\nScan the QR code text from the image:</p>\n<pre><code>zbarimg image.png\n</code></pre>\n<p>An example QR code:</p>\n<p><img src="downloads/2fa/qr.png" alt="QR code example" /></p>\n<p>The output is typically something like:</p>\n<pre><code>QR-Code:otpauth://totp/Example:someuser@codemadness.org?secret=SECRETKEY&amp;issuer=Codemadness\n</code></pre>\n<p>You only need to scan this QR-code for the secret key once.\nMake sure to store the secret key in a private safe place and don't show it to\nanyone else.</p>\n<p>Using the secret key the following command outputs a 6-digit code by default.\nIn this example we also assume the key is base32-encoded.\nThere can be other parameters and options, this is documented in the Yubico URI\nstring format reference below.</p>\n<p>Command:</p>\n<pre><code>oathtool --totp -b SOMEKEY\n</code></pre>\n<ul>\n<li>The --totp option uses the time-variant TOTP mode, by default it uses HMAC SHA1.</li>\n<li>The -b option uses base32 encoding of KEY instead of hex.</li>\n</ul>\n<p>Tip: you can create a script that automatically puts the digits in the\nclipboard, for example:</p>\n<pre><code>oathtool --totp -b SOMEKEY | xclip\n</code></pre>\n<h2>References</h2>\n<ul>\n<li><a href="https://linux.die.net/man/1/zbarimg">zbarimg(1) man page</a></li>\n<li><a href="https://www.nongnu.org/oath-toolkit/man-oathtool.html">oathtool(1) man page</a></li>\n<li><a href="https://datatracker.ietf.org/doc/html/rfc6238">RFC6238 - TOTP: Time-Based One-Time Password Algorithm</a></li>\n<li><a href="https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html">Yubico.com - otpauth URI string format</a></li>\n</ul>        html        gopher://codemadness.org/1/phlog/totp        Hiltjo                
        1634947200        Setup an OpenBSD RISCV64 VM in QEMU        gopher://codemadness.org/1/phlog/openbsd-riscv64-vm        <h1>Setup an OpenBSD RISCV64 VM in QEMU</h1>\n\t<p><strong>Last modification on </strong> <time>2021-10-26</time></p>\n\t<p>This describes how to setup an OpenBSD RISCV64 VM in QEMU.</p>\n<p>The shellscript below does the following:</p>\n<ul>\n<li>Set up the disk image (raw format).</li>\n<li>Patch the disk image with the OpenBSD miniroot file for the installation.</li>\n<li>Downloads the opensbi and u-boot firmware files for qemu.</li>\n<li>Run the VM with the supported settings.</li>\n</ul>\n<p>The script is tested on the host GNU/Void Linux and OpenBSD-current.</p>\n<p><strong>IMPORTANT!: The signature and checksum for the miniroot, u-boot and opensbi\nfiles are not verified. If the host is OpenBSD make sure to instead install the\npackages (pkg_add u-boot-riscv64 opensbi) and adjust the firmware path for the\nqemu -bios and -kernel options. </strong></p>\n<h2>Shellscript</h2>\n<pre><code>#!/bin/sh\n# mirror list: https://www.openbsd.org/ftp.html\nmirror="https://ftp.bit.nl/pub/OpenBSD/"\nrelease="7.0"\nminirootname="miniroot70.img"\n\nminiroot() {\n\ttest -f "${minirootname}" &amp;&amp; return # download once\n\n\turl="${mirror}/${release}/riscv64/${minirootname}"\n\tcurl -o "${minirootname}" "${url}"\n}\n\ncreaterootdisk() {\n\ttest -f disk.raw &amp;&amp; return # create once\n\tqemu-img create disk.raw 10G # create 10 GB disk\n\tdd conv=notrunc if=${minirootname} of=disk.raw # write miniroot to disk\n}\n\nopensbi() {\n\tf="opensbi.tgz"\n\ttest -f "${f}" &amp;&amp; return # download and extract once.\n\n\turl="${mirror}/${release}/packages/amd64/opensbi-0.9p0.tgz"\n\tcurl -o "${f}" "${url}"\n\n\ttar -xzf "${f}" share/opensbi/generic/fw_jump.bin\n}\n\nuboot() {\n\tf="uboot.tgz"\n\ttest -f "${f}" &amp;&amp; return # download and extract once.\n\n\turl="${mirror}/${release}/packages/amd64/u-boot-riscv64-2021.07p0.tgz"\n\tcurl -o "${f}" "${url}"\n\n\ttar -xzf "${f}" share/u-boot/qemu-riscv64_smode/u-boot.bin\n}\n\nsetup() {\n\tminiroot\n\tcreaterootdisk\n\topensbi\n\tuboot\n}\n\nrun() {\n\tqemu-system-riscv64 \\\n\t\t-machine virt \\\n\t\t-nographic \\\n\t\t-m 2048M \\\n\t\t-smp 2 \\\n\t\t-bios share/opensbi/generic/fw_jump.bin \\\n\t\t-kernel share/u-boot/qemu-riscv64_smode/u-boot.bin \\\n\t\t-drive file=disk.raw,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 \\\n\t\t-netdev user,id=net0,ipv6=off -device virtio-net-device,netdev=net0\n}\n\nsetup\nrun\n</code></pre>        html        gopher://codemadness.org/1/phlog/openbsd-riscv64-vm        Hiltjo                
       -1593043200        Sfeed_curses: a curses UI front-end for sfeed        gopher://codemadness.org/1/phlog/sfeed_curses        <h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2022-05-08</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href="http://www.mutt.org/">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) supporting UTF-8.</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Quite fast.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href="downloads/screenshots/sfeed_curses_screenshot.png"><img src="downloads/screenshots/sfeed_curses_screenshot.png" alt="Screenshot showing what the UI looks" width="480" height="270" loading="lazy" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href="https://portland.freedesktop.org/doc/xdg-open.html">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>\n<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a> shellscript which uses\nthe <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or "less").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href="https://www.dillo.org/">dillo</a></li>\n<li><a href="http://www.jikos.cz/~mikulas/links/">links</a></li>\n<li><a href="http://w3m.sourceforge.net/">w3m</a></li>\n<li><a href="https://git.codemadness.org/webdump/file/README.html">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href="https://templeos.org/">TempleOS</a>-like color-theme on the right a\n<a href="https://newsboat.org/">newsboat</a>-like colorscheme.</p>\n<p><a href="downloads/screenshots/sfeed_curses_theme_screenshot.png"><img src="downloads/screenshots/sfeed_curses_theme_screenshot.png" alt="Screenshot showing a custom colorscheme" width="480" height="270" loading="lazy" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href="downloads/screenshots/sfeed_curses_horizontal_screenshot.png"><img src="downloads/screenshots/sfeed_curses_horizontal_screenshot.png" alt="Screenshot showing the horizontal layout" width="480" height="270" loading="lazy" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/sfeed/">https://git.codemadness.org/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/git/sfeed">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/sfeed/">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/sfeed">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>        html        gopher://codemadness.org/1/phlog/sfeed_curses        Hiltjo                
       +1593043200        Sfeed_curses: a curses UI front-end for sfeed        gopher://codemadness.org/1/phlog/sfeed_curses        <h1>Sfeed_curses: a curses UI front-end for sfeed</h1>\n\t<p><strong>Last modification on </strong> <time>2025-07-24</time></p>\n\t<p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.\nIt is now part of sfeed.</p>\n<p>It shows the TAB-separated feed items in a graphical command-line UI.  The\ninterface has a look inspired by the <a href="http://www.mutt.org/">mutt mail client</a>. It has a sidebar\npanel for the feeds, a panel with a listing of the items and a small statusbar\nfor the selected item/URL. Some functions like searching and scrolling are\nintegrated in the interface itself.</p>\n<h2>Features</h2>\n<ul>\n<li>Relatively few LOC, about 2.5K lines of C.</li>\n<li>Few dependencies: a C compiler and a curses library (typically ncurses).\nIt also requires a terminal (emulator) which supports UTF-8.\n<ul>\n<li>xterm-compatible shim <a href="https://git.codemadness.org/sfeed/file/minicurses.h.html">minicurses.h</a></li>\n</ul>\n</li>\n<li>Easy to customize by modifying the small source-code and shellscripts.</li>\n<li>Plumb support: open the URL or an enclosure URL directly with any program.</li>\n<li>Pipe support: pipe the selected Tab-Separated Value line to a program for\nscripting purposes. Like viewing the content in any way you like.</li>\n<li>Yank support: copy the URL or an enclosure URL to the clipboard.</li>\n<li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for\nactions.</li>\n<li>Mouse support: it supports xterm X10 and extended SGR encoding.</li>\n<li>Support two ways of managing read/unread items.\nBy default sfeed_curses marks the feed items of the last day as new/bold.\nAlternatively a simple plain-text list with the read URLs can be used.</li>\n<li>UI layouts: supports vertical, horizontal and monocle (full-screen) layouts.\nUseful for different kind of screen sizes.</li>\n<li>Auto-execute keybind commands at startup to automate setting a preferred\nlayout, toggle showing new items or other actions.</li>\n</ul>\n<p>Like the format programs included in sfeed you can run it by giving the feed\nfiles as arguments like this:</p>\n<pre><code>sfeed_curses ~/.sfeed/feeds/*\n</code></pre>\n<p>... or by reading directly from stdin:</p>\n<pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd\n</code></pre>\n<p>It will show a sidebar if one or more files are specified as parameters. It\nwill not show the sidebar by default when reading from stdin.</p>\n<p><a href="downloads/screenshots/sfeed_curses_screenshot.png"><img src="downloads/screenshots/sfeed_curses_screenshot.png" alt="Screenshot showing what the UI looks" width="480" height="270" loading="lazy" /></a></p>\n<p>On pressing the 'o' or ENTER keybind it will open the link URL of an item with\nthe plumb program.  On pressing the 'a', 'e' or '@' keybind it will open the\nenclosure URL if there is one.  The default plumb program is set to <a href="https://portland.freedesktop.org/doc/xdg-open.html">xdg-open</a>,\nbut can be modified by setting the environment variable $SFEED_PLUMBER.  The\nplumb program receives the URL as a command-line argument.</p>\n<p>The TAB-Separated-Value line of the current selected item in the feed file can\nbe piped to a program by pressing the 'c', 'p' or '|' keybind. This allows much\nflexibility to make a content formatter or write other custom actions or views.\nThis line is in the exact same format as described in the sfeed(5) man page.</p>\n<p>The pipe program can be changed by setting the environment variable\n$SFEED_PIPER.</p>\n<p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>\n<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed/file/sfeed_content.html">sfeed_content</a> shellscript which uses\nthe <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted\nplain-text to the user $PAGER (or "less").</p>\n<p>Of course the script can be easily changed to use a different browser or\nHTML-to-text converter like:</p>\n<ul>\n<li><a href="https://www.dillo.org/">dillo</a></li>\n<li><a href="http://www.jikos.cz/~mikulas/links/">links</a></li>\n<li><a href="http://w3m.sourceforge.net/">w3m</a></li>\n<li><a href="https://git.codemadness.org/webdump/file/README.html">webdump</a></li>\n</ul>\n<p>It's easy to modify the color-theme by changing the macros in the source-code\nor set a predefined theme at compile-time. The README file contains information\nhow to set a theme.  On the left a <a href="https://templeos.org/">TempleOS</a>-like color-theme on the right a\n<a href="https://newsboat.org/">newsboat</a>-like colorscheme.</p>\n<p><a href="downloads/screenshots/sfeed_curses_theme_screenshot.png"><img src="downloads/screenshots/sfeed_curses_theme_screenshot.png" alt="Screenshot showing a custom colorscheme" width="480" height="270" loading="lazy" /></a></p>\n<p>It supports a vertical layout, horizontal and monocle (full-screen) layout.\nThis can be useful for different kind of screen sizes.  The keybinds '1', '2'\nand '3' can be used to switch between these layouts.</p>\n<p><a href="downloads/screenshots/sfeed_curses_horizontal_screenshot.png"><img src="downloads/screenshots/sfeed_curses_horizontal_screenshot.png" alt="Screenshot showing the horizontal layout" width="480" height="270" loading="lazy" /></a></p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/sfeed\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/sfeed/">https://git.codemadness.org/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/git/sfeed">gopher://codemadness.org/1/git/sfeed</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/sfeed/">https://codemadness.org/releases/sfeed/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/sfeed">gopher://codemadness.org/1/releases/sfeed</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>        html        gopher://codemadness.org/1/phlog/sfeed_curses        Hiltjo                
        1573344000        hurl: HTTP, HTTPS and Gopher file grabber        gopher://codemadness.org/1/phlog/hurl        <h1>hurl: HTTP, HTTPS and Gopher file grabber</h1>\n\t<p><strong>Last modification on </strong> <time>2020-07-20</time></p>\n\t<p>hurl is a relatively simple HTTP, HTTPS and Gopher client/file grabber.</p>\n<h2>Why?</h2>\n<p>Sometimes (or most of the time?) you just want to fetch a file via the HTTP,\nHTTPS or Gopher protocol.</p>\n<p>The focus of this tool is only this.</p>\n<h2>Features</h2>\n<ul>\n<li>Uses OpenBSD pledge(2) and unveil(2). Allow no filesystem access (writes to\nstdout).</li>\n<li>Impose time-out and maximum size limits.</li>\n<li>Use well-defined exitcodes for reliable scripting (curl sucks at this).</li>\n<li>Send as little information as possible (no User-Agent etc by default).</li>\n</ul>\n<h2>Anti-features</h2>\n<ul>\n<li>No HTTP byte range support.</li>\n<li>No HTTP User-Agent.</li>\n<li>No HTTP If-Modified-Since/If-* support.</li>\n<li>No HTTP auth support.</li>\n<li>No HTTP/2+ support.</li>\n<li>No HTTP keep-alive.</li>\n<li>No HTTP chunked-encoding support.</li>\n<li>No HTTP redirect support.</li>\n<li>No (GZIP) compression support.</li>\n<li>No cookie-jar or cookie parsing support.</li>\n<li>No Gopher text handling (".\\r\\n").</li>\n<li>... etc...</li>\n</ul>\n<h2>Dependencies</h2>\n<ul>\n<li>C compiler (C99).</li>\n<li>libc + some BSD functions like err() and strlcat().</li>\n<li>LibreSSL(-portable)</li>\n<li>libtls (part of LibreSSL).</li>\n</ul>\n<h2>Optional dependencies</h2>\n<ul>\n<li>POSIX make(1) (for Makefile).</li>\n<li>mandoc for documentation: <a href="https://mdocml.bsd.lv/">https://mdocml.bsd.lv/</a></li>\n</ul>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/hurl\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/hurl/">https://git.codemadness.org/hurl/</a></li>\n<li><a href="gopher://codemadness.org/1/git/hurl">gopher://codemadness.org/1/git/hurl</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/hurl/">https://codemadness.org/releases/hurl/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/hurl">gopher://codemadness.org/1/releases/hurl</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>\n<h2>Examples</h2>\n<p>Fetch the Atom feed from this site using a maximum filesize limit of 1MB and\na time-out limit of 15 seconds:</p>\n<pre><code>hurl -m 1048576 -t 15 "https://codemadness.org/atom.xml"\n</code></pre>\n<p>There is an -H option to add custom headers. This way some of the anti-features\nlisted above are supported. For example some CDNs like Cloudflare are known to\nblock empty or certain User-Agents.</p>\n<p>User-Agent:</p>\n<pre><code>hurl -H 'User-Agent: some browser' 'https://codemadness.org/atom.xml'\n</code></pre>\n<p>HTTP Basic Auth (base64-encoded username:password):</p>\n<pre><code>hurl -H 'Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=' \\\n\t'https://codemadness.org/atom.xml'\n</code></pre>\n<p>GZIP (this assumes the served response Content-Type is gzip):</p>\n<pre><code>hurl -H 'Accept-Encoding: gzip' 'https://somesite/' | gzip -d\n</code></pre>        html        gopher://codemadness.org/1/phlog/hurl        Hiltjo                
        1570924800        json2tsv: a JSON to TSV converter        gopher://codemadness.org/1/phlog/json2tsv        <h1>json2tsv: a JSON to TSV converter</h1>\n\t<p><strong>Last modification on </strong> <time>2021-09-25</time></p>\n\t<p>Convert JSON to TSV or separated output.</p>\n<p>json2tsv reads JSON data from stdin.  It outputs each JSON type to a TAB-\nSeparated Value format per line by default.</p>\n<h2>TAB-Separated Value format</h2>\n<p>The output format per line is:</p>\n<pre><code>nodename&lt;TAB&gt;type&lt;TAB&gt;value&lt;LF&gt;\n</code></pre>\n<p>Control-characters such as a newline, TAB and backslash (\\n, \\t and \\) are\nescaped in the nodename and value fields.  Other control-characters are\nremoved.</p>\n<p>The type field is a single byte and can be:</p>\n<ul>\n<li>a for array</li>\n<li>b for bool</li>\n<li>n for number</li>\n<li>o for object</li>\n<li>s for string</li>\n<li>? for null</li>\n</ul>\n<p>Filtering on the first field "nodename" is easy using awk for example.</p>\n<h2>Features</h2>\n<ul>\n<li>Accepts all <strong>valid</strong> JSON.</li>\n<li>Designed to work well with existing UNIX programs like awk and grep.</li>\n<li>Straightforward and not much lines of code: about 475 lines of C.</li>\n<li>Few dependencies: C compiler (C99), libc.</li>\n<li>No need to learn a new (meta-)language for processing data.</li>\n<li>The parser supports code point decoding and UTF-16 surrogates to UTF-8.</li>\n<li>It does not output control-characters to the terminal for security reasons by\ndefault (but it has a -r option if needed).</li>\n<li>On OpenBSD it supports <a href="https://man.openbsd.org/pledge">pledge(2)</a> for syscall restriction:\npledge("stdio", NULL).</li>\n<li>Supports setting a different field separator and record separator with the -F\nand -R option.</li>\n</ul>\n<h2>Cons</h2>\n<ul>\n<li>For the tool there is additional overhead by processing and filtering data\nfrom stdin after parsing.</li>\n<li>The parser does not do complete validation on numbers.</li>\n<li>The parser accepts some bad input such as invalid UTF-8\n(see <a href="https://tools.ietf.org/html/rfc8259#section-8.1">RFC8259 - 8.1. Character Encoding</a>).\njson2tsv reads from stdin and does not do assumptions about a "closed\necosystem" as described in the RFC.</li>\n<li>The parser accepts some bad JSON input and "extensions"\n(see <a href="https://tools.ietf.org/html/rfc8259#section-9">RFC8259 - 9. Parsers</a>).</li>\n<li>Encoded NUL bytes (\\u0000) in strings are ignored.\n(see <a href="https://tools.ietf.org/html/rfc8259#section-9">RFC8259 - 9. Parsers</a>).\n"An implementation may set limits on the length and character contents of\nstrings."</li>\n<li>The parser is not the fastest possible JSON parser (but also not the\nslowest).  For example: for ease of use, at the cost of performance all\nstrings are decoded, even though they may be unused.</li>\n</ul>\n<h2>Why Yet Another JSON parser?</h2>\n<p>I wanted a tool that makes parsing JSON easier and work well from the shell,\nsimilar to <a href="https://stedolan.github.io/jq/">jq</a>.</p>\n<p>sed and grep often work well enough for matching some value using some regex\npattern, but it is not good enough to parse JSON correctly or to extract all\ninformation: just like parsing HTML/XML using some regex is not good (enough)\nor a good idea :P.</p>\n<p>I didn't want to learn a new specific <a href="https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions">meta-language</a> which jq has and wanted\nsomething simpler.</p>\n<p>While it is more efficient to embed this query language for data aggregation,\nit is also less simple. In my opinion it is simpler to separate this and use\npattern-processing by awk or an other filtering/aggregating program.</p>\n<p>For the parser, there are many JSON parsers out there, like the efficient\n<a href="https://github.com/zserge/jsmn">jsmn parser</a>, however a few parser behaviours I want to have are:</p>\n<ul>\n<li>jsmn buffers data as tokens, which is very efficient, but also a bit\nannoying as an API as it requires another layer of code to interpret the\ntokens.</li>\n<li>jsmn does not handle decoding strings by default. Which is very efficient\nif you don't need parts of the data though.</li>\n<li>jsmn does not keep context of nested structures by default, so may require\nwriting custom utility functions for nested data.</li>\n</ul>\n<p>This is why I went for a parser design that uses a single callback per "node"\ntype and keeps track of the current nested structure in a single array and\nemits that.</p>\n<h2>Clone</h2>\n<pre><code>git clone git://git.codemadness.org/json2tsv\n</code></pre>\n<h2>Browse</h2>\n<p>You can browse the source-code at:</p>\n<ul>\n<li><a href="https://git.codemadness.org/json2tsv/">https://git.codemadness.org/json2tsv/</a></li>\n<li><a href="gopher://codemadness.org/1/git/json2tsv">gopher://codemadness.org/1/git/json2tsv</a></li>\n</ul>\n<h2>Download releases</h2>\n<p>Releases are available at:</p>\n<ul>\n<li><a href="https://codemadness.org/releases/json2tsv/">https://codemadness.org/releases/json2tsv/</a></li>\n<li><a href="gopher://codemadness.org/1/releases/json2tsv">gopher://codemadness.org/1/releases/json2tsv</a></li>\n</ul>\n<h2>Build and install</h2>\n<pre><code>$ make\n# make install\n</code></pre>\n<h2>Examples</h2>\n<p>An usage example to parse posts of the JSON API of <a href="https://www.reddit.com/">reddit.com</a> and format them\nto a plain-text list using awk:</p>\n<pre><code>#!/bin/sh\ncurl -s -H 'User-Agent:' 'https://old.reddit.com/.json?raw_json=1&amp;limit=100' | \\\njson2tsv | \\\nawk -F '\\t' '\nfunction show() {\n\tif (length(o["title"]) == 0)\n\t\treturn;\n\tprint n ". " o["title"] " by " o["author"] " in r/" o["subreddit"];\n\tprint o["url"];\n\tprint "";\n}\n$1 == ".data.children[].data" {\n\tshow();\n\tn++;\n\tdelete o;\n}\n$1 ~ /^\\.data\\.children\\[\\]\\.data\\.[a-zA-Z0-9_]*$/ {\n\to[substr($1, 23)] = $3;\n}\nEND {\n\tshow();\n}'\n</code></pre>\n<h2>References</h2>\n<ul>\n<li>Sites:\n<ul>\n<li><a href="http://seriot.ch/parsing_json.php">seriot.ch - Parsing JSON is a Minefield</a></li>\n<li><a href="https://github.com/nst/JSONTestSuite">A comprehensive test suite for RFC 8259 compliant JSON parsers</a></li>\n<li><a href="https://json.org/">json.org</a></li>\n</ul>\n</li>\n<li>Current standard:\n<ul>\n<li><a href="https://tools.ietf.org/html/rfc8259">RFC8259 - The JavaScript Object Notation (JSON) Data Interchange Format</a></li>\n<li><a href="https://www.ecma-international.org/publications/standards/Ecma-404.htm">Standard ECMA-404 - The JSON Data Interchange Syntax (2nd edition (December 2017)</a></li>\n</ul>\n</li>\n<li>Historic standards:\n<ul>\n<li><a href="https://tools.ietf.org/html/rfc7159">RFC7159 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete)</a></li>\n<li><a href="https://tools.ietf.org/html/rfc7158">RFC7158 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete)</a></li>\n<li><a href="https://tools.ietf.org/html/rfc4627">RFC4627 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete, original)</a></li>\n</ul>\n</li>\n</ul>        html        gopher://codemadness.org/1/phlog/json2tsv        Hiltjo                
        1556064000        OpenBSD: setup a local auto-installation server        gopher://codemadness.org/1/phlog/openbsd-autoinstall        <h1>OpenBSD: setup a local auto-installation server</h1>\n\t<p><strong>Last modification on </strong> <time>2020-04-30</time></p>\n\t<p>This guide describes how to setup a local mirror and installation/upgrade\nserver that requires little or no input interaction.</p>\n<h2>Setup a local HTTP mirror</h2>\n<p>The HTTP mirror will be used to fetch the base sets and (optional) custom sets.\nIn this guide we will assume <strong>192.168.0.2</strong> is the local installation server\nand mirror, the CPU architecture is amd64 and the OpenBSD release version is\n6.5.  We will store the files in the directory with the structure:</p>\n<pre><code>http://192.168.0.2/pub/OpenBSD/6.5/amd64/\n</code></pre>\n<p>Create the www serve directory and fetch all sets and install files\n(if needed to save space *.iso and install65.fs can be skipped):</p>\n<pre><code>$ cd /var/www/htdocs\n$ mkdir -p pub/OpenBSD/6.5/amd64/\n$ cd pub/OpenBSD/6.5/amd64/\n$ ftp 'ftp://ftp.nluug.nl/pub/OpenBSD/6.5/amd64/*'\n</code></pre>\n<p>Verify signature and check some checksums:</p>\n<pre><code>$ signify -C -p /etc/signify/openbsd-65-base.pub -x SHA256.sig\n</code></pre>\n<p>Setup <a href="https://man.openbsd.org/httpd.8">httpd(8)</a> for simple file serving:</p>\n<pre><code># $FAVORITE_EDITOR /etc/httpd.conf\n</code></pre>\n<p>A minimal example config for <a href="https://man.openbsd.org/httpd.conf.5">httpd.conf(5)</a>:</p>\n<pre><code>server "*" {\n\tlisten on * port 80\n}\n</code></pre>\n<p>The default www root directory is: /var/www/htdocs/</p>\n<p>Enable the httpd daemon to start by default and start it now:</p>\n<pre><code># rcctl enable httpd\n# rcctl start httpd\n</code></pre>\n<h2>Creating an installation response/answer file</h2>\n<p>The installer supports loading responses to the installation/upgrade questions\nfrom a simple text file. We can do a regular installation and copy the answers\nfrom the saved file to make an automated version of it.</p>\n<p>Do a test installation, at the end of the installation or upgrade when asked the\nquestion:</p>\n<pre><code>Exit to (S)hell, (H)alt or (R)eboot?\n</code></pre>\n<p>Type S to go to the shell. Find the response file for an installation and copy\nit to some USB stick or write down the response answers:</p>\n<pre><code>cp /tmp/i/install.resp /mnt/usbstick/\n</code></pre>\n<p>A response file could be for example:</p>\n<pre><code>System hostname = testvm\nWhich network interface do you wish to configure = em0\nIPv4 address for em0 = dhcp\nIPv6 address for em0 = none\nWhich network interface do you wish to configure = done\nPassword for root account = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.\nPassword for user testuser = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.\nStart sshd(8) by default = no\nDo you expect to run the X Window System = no\nSetup a user = testuser\nFull name for user testuser = testuser\nWhat timezone are you in = Europe/Amsterdam\nWhich disk is the root disk = wd0\nUse (W)hole disk MBR, whole disk (G)PT, (O)penBSD area or (E)dit = OpenBSD\nUse (A)uto layout, (E)dit auto layout, or create (C)ustom layout = a\nLocation of sets = http\nHTTP proxy URL = none\nHTTP Server = 192.168.0.2\nServer directory = pub/OpenBSD/6.5/amd64\nUnable to connect using https. Use http instead = yes\nLocation of sets = http\nSet name(s) = done\nLocation of sets = done\nExit to (S)hell, (H)alt or (R)eboot = R\n</code></pre>\n<p>Get custom encrypted password for response file:</p>\n<pre><code>$ printf '%s' 'yourpassword' | encrypt\n</code></pre>\n<h2>Changing the RAMDISK kernel disk image</h2>\n<p><a href="https://man.openbsd.org/rdsetroot.8">rdsetroot(8)</a> is publicly exposed now in base since 6.5. Before 6.5 it is\navailable in the /usr/src/ tree as elfrdsetroot, see also the <a href="https://man.openbsd.org/rd.4">rd(4)</a> man page.</p>\n<pre><code>$ mkdir auto\n$ cd auto\n$ cp pubdir/bsd.rd .\n$ rdsetroot -x bsd.rd disk.fs\n# vnconfig vnd0 disk.fs\n# mkdir mount\n# mount /dev/vnd0a mount\n</code></pre>\n<p>Copy the response file (install.resp) to: mount/auto_install.conf\n(installation) <strong>or</strong> mount/auto_upgrade.conf (upgrade), but not both. In this\nguide we will do an auto-installation.</p>\n<p>Unmount, detach and patch RAMDISK:</p>\n<pre><code># umount mount\n# vnconfig -u vnd0\n$ rdsetroot bsd.rd disk.fs\n</code></pre>\n<p>To test copy bsd.rd to the root of some testmachine like /bsd.test.rd then\n(re)boot and type:</p>\n<pre><code>boot /bsd.test.rd\n</code></pre>\n<p>In the future (6.5+) it will be possible to copy to a file named "/bsd.upgrade"\nin the root of a current system and automatically load the kernel:\n<a href="https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/stand/boot/boot.c?rev=1.46&amp;content-type=text/x-cvsweb-markup">See the script bsd.upgrade in CVS.</a>\nOf course this is possible with PXE boot or some custom USB/ISO also.\nAs explained in the <a href="https://man.openbsd.org/autoinstall.8">autoinstall(8)</a> man page: create either an\nauto_upgrade.conf <strong>or</strong> an auto_install.conf, but not both.</p>\n<h2>Create bootable miniroot</h2>\n<p>In this example the miniroot will boot the custom kernel, but fetch all the\nsets from the local network.</p>\n<p>We will base our miniroot of the official version: miniroot65.fs.</p>\n<p>We will create a 16MB miniroot to boot from (in this guide it is assumed the\noriginal miniroot is about 4MB and the modified kernel image fits in the new\nallocated space):</p>\n<pre><code>$ dd if=/dev/zero of=new.fs bs=512 count=32768\n</code></pre>\n<p>Copy first part of the original image to the new disk (no truncation):</p>\n<pre><code>$ dd conv=notrunc if=miniroot65.fs of=new.fs\n# vnconfig vnd0 new.fs\n</code></pre>\n<p>Expand disk OpenBSD boundaries:</p>\n<pre><code># disklabel -E vnd0\n&gt; b\nStarting sector: [1024]\nSize ('*' for entire disk): [8576] *\n&gt; r\nTotal free sectors: 1168.\n&gt; c a\nPartition a is currently 8576 sectors in size, and can have a maximum\nsize of 9744 sectors.\nsize: [8576] *\n&gt; w\n&gt; q\n</code></pre>\n<p>or:</p>\n<pre><code># printf 'b\\n\\n*\\nc a\\n*\\nw\\n' | disklabel -E vnd0\n</code></pre>\n<p>Grow filesystem and check it and mark as clean:</p>\n<pre><code># growfs -y /dev/vnd0a\n# fsck -y /dev/vnd0a\n</code></pre>\n<p>Mount filesystem:</p>\n<pre><code># mount /dev/vnd0a mount/\n</code></pre>\n<p>The kernel on the miniroot is GZIP compressed. Compress our modified bsd.rd and\noverwrite the original kernel:</p>\n<pre><code># gzip -c9n bsd.rd &gt; mount/bsd\n</code></pre>\n<p>Or to save space (+- 500KB) by stripping debug symbols, taken from bsd.gz target\n<a href="https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/distrib/amd64/iso/Makefile">in this Makefile</a>.</p>\n<pre><code>$ cp bsd.rd bsd.strip\n$ strip bsd.strip\n$ strip -R .comment -R .SUNW_ctf bsd.strip\n$ gzip -c9n bsd.strip &gt; bsd.gz\n$ cp bsd.gz mount/bsd\n</code></pre>\n<p>Now unmount and detach:</p>\n<pre><code># umount mount/\n# vnconfig -u vnd0\n</code></pre>\n<p>Now you can <a href="https://man.openbsd.org/dd.1">dd(1)</a> the image new.fs to your bootable (USB) medium.</p>\n<h2>Adding custom sets (optional)</h2>\n<p>For patching <a href="https://man.openbsd.org/rc.firsttime.8">/etc/rc.firsttime</a> and other system files it is useful to use a\ncustomized installation set like siteVERSION.tgz, for example: site65.tgz.  The\nsets can even be specified per host/MAC address like\nsiteVERSION-$(hostname -s).tgz so for example: site65-testvm.tgz</p>\n<p>When the installer checks the base sets of the mirror it looks for a file\nindex.txt.  To add custom sets the site entries have to be added.</p>\n<p>For example:</p>\n<pre><code>-rw-r--r--  1 1001  0    4538975 Oct 11 13:58:26 2018 site65-testvm.tgz\n</code></pre>\n<p>The filesize, permissions etc do not matter and are not checked by the\ninstaller.  Only the filename is matched by a regular expression.</p>\n<h2>Sign custom site* tarball sets (optional)</h2>\n<p>If you have custom sets without creating a signed custom release you will be\nprompted for the messages:</p>\n<pre><code>checksum test failed\n</code></pre>\n<p>and:</p>\n<pre><code>unverified sets: continue without verification\n</code></pre>\n<p>OpenBSD uses the program <a href="https://man.openbsd.org/signify.1">signify(1)</a> to cryptographically sign and\nverify filesets.</p>\n<p>To create a custom public/private keypair (ofcourse make sure to store the\nprivate key privately):</p>\n<pre><code>$ signify -G -n -c "Custom 6.5 install" -p custom-65-base.pub -s custom-65-base.sec\n</code></pre>\n<p>Create new checksum file with filelist of the current directory (except SHA256*\nfiles):</p>\n<pre><code>$ printf '%s\\n' * | grep -v SHA256 | xargs sha256 &gt; SHA256\n</code></pre>\n<p>Sign SHA256 and store as SHA256.sig, embed signature:</p>\n<pre><code>$ signify -S -e -s /privatedir/custom-65-base.sec -m SHA256 -x SHA256.sig\n</code></pre>\n<p>Verify the created signature and data is correct:</p>\n<pre><code>$ signify -C -p /somelocation/custom-65-base.pub -x SHA256.sig\n</code></pre>\n<p>Copy <strong>only</strong> the <strong>public</strong> key to the RAMDISK:</p>\n<pre><code>$ cp custom-65-base.pub mount/etc/signify/custom-65-base.pub\n</code></pre>\n<p>Now we have to patch the install.sub file to check our public key.  If you know\na better way without having to patch this script, please let me know.</p>\n<p>Change the variable PUB_KEY in the shellscript mount/install.sub from:</p>\n<pre><code>PUB_KEY=/etc/signify/openbsd-${VERSION}-base.pub\n</code></pre>\n<p>To:</p>\n<pre><code>PUB_KEY=/etc/signify/custom-${VERSION}-base.pub\n</code></pre>\n<p>And for upgrades from:</p>\n<pre><code>$UPGRADE_BSDRD &amp;&amp;\n\tPUB_KEY=/mnt/etc/signify/openbsd-$((VERSION + 1))-base.pub\n</code></pre>\n<p>To:</p>\n<pre><code>$UPGRADE_BSDRD &amp;&amp;\n\tPUB_KEY=/mnt/etc/signify/custom-$((VERSION + 1))-base.pub\n</code></pre>\n<h2>Ideas</h2>\n<ul>\n<li>Patch <a href="https://man.openbsd.org/rc.firsttime.8">rc.firsttime(8)</a>: and run syspatch, add ports, setup xenodm etc.</li>\n<li>Custom partitioning scheme, see <a href="https://man.openbsd.org/autoinstall.8">autoinstall(8)</a> "URL to autopartitioning\ntemplate for disklabel = url".</li>\n<li>Setup <a href="https://man.openbsd.org/pxeboot.8">pxeboot(8)</a> to boot and install over the network using\n<a href="https://man.openbsd.org/dhcpd.8">dhcpd(8)</a> and\n<a href="https://man.openbsd.org/tftpd.8">tftpd(8)</a> then not even some USB stick is required.</li>\n</ul>\n<h2>References</h2>\n<ul>\n<li>Main OpenBSD installation and upgrade shellscript:\n<a href="https://cvsweb.openbsd.org/src/distrib/miniroot/install.sub">/usr/src/distrib/miniroot/install.sub</a></li>\n</ul>        html        gopher://codemadness.org/1/phlog/openbsd-autoinstall        Hiltjo                
 (DIR) diff --git a/output/sfeed_curses-ui.html b/output/sfeed_curses-ui.html
       @@ -42,7 +42,7 @@
        <header>
                <h1>Sfeed_curses: a curses UI front-end for sfeed</h1>
                <p>
       -        <strong>Last modification on </strong> <time>2022-05-08</time>
       +        <strong>Last modification on </strong> <time>2025-07-24</time>
                </p>
        </header>
        
       @@ -57,9 +57,12 @@ integrated in the interface itself.</p>
        <ul>
        <li>Relatively few LOC, about 2.5K lines of C.</li>
        <li>Few dependencies: a C compiler and a curses library (typically ncurses).
       -It also requires a terminal (emulator) supporting UTF-8.</li>
       +It also requires a terminal (emulator) which supports UTF-8.
       +<ul>
       +<li>xterm-compatible shim <a href="https://git.codemadness.org/sfeed/file/minicurses.h.html">minicurses.h</a></li>
       +</ul>
       +</li>
        <li>Easy to customize by modifying the small source-code and shellscripts.</li>
       -<li>Quite fast.</li>
        <li>Plumb support: open the URL or an enclosure URL directly with any program.</li>
        <li>Pipe support: pipe the selected Tab-Separated Value line to a program for
        scripting purposes. Like viewing the content in any way you like.</li>
       @@ -97,7 +100,7 @@ This line is in the exact same format as described in the sfeed(5) man page.</p>
        <p>The pipe program can be changed by setting the environment variable
        $SFEED_PIPER.</p>
        <p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" alt="Screenshot showing the output of the pipe content script" width="480" height="270" loading="lazy" /></a></p>
       -<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a> shellscript which uses
       +<p>The above screenshot shows the included <a href="https://git.codemadness.org/sfeed/file/sfeed_content.html">sfeed_content</a> shellscript which uses
        the <a href="https://invisible-island.net/lynx/">lynx text-browser</a> to convert HTML to plain-text.  It pipes the formatted
        plain-text to the user $PAGER (or "less").</p>
        <p>Of course the script can be easily changed to use a different browser or
 (DIR) diff --git a/output/sfeed_curses-ui.md b/output/sfeed_curses-ui.md
       @@ -12,9 +12,9 @@ integrated in the interface itself.
        
        * Relatively few LOC, about 2.5K lines of C.
        * Few dependencies: a C compiler and a curses library (typically ncurses).
       -  It also requires a terminal (emulator) supporting UTF-8.
       +  It also requires a terminal (emulator) which supports UTF-8.
       +  * xterm-compatible shim [minicurses.h](https://git.codemadness.org/sfeed/file/minicurses.h.html)
        * Easy to customize by modifying the small source-code and shellscripts.
       -* Quite fast.
        * Plumb support: open the URL or an enclosure URL directly with any program.
        * Pipe support: pipe the selected Tab-Separated Value line to a program for
          scripting purposes. Like viewing the content in any way you like.
       @@ -61,7 +61,7 @@ $SFEED_PIPER.
        
        [![Screenshot showing the output of the pipe content script](https://codemadness.org/downloads/screenshots/sfeed_curses_pipe_screenshot.png =480x270)](https://codemadness.org/downloads/screenshots/sfeed_curses_pipe_screenshot.png)
        
       -The above screenshot shows the included [sfeed_content](https://git.codemadness.org/sfeed_curses/file/sfeed_content.html) shellscript which uses
       +The above screenshot shows the included [sfeed_content](https://git.codemadness.org/sfeed/file/sfeed_content.html) shellscript which uses
        the [lynx text-browser](https://invisible-island.net/lynx/) to convert HTML to plain-text.  It pipes the formatted
        plain-text to the user $PAGER (or "less").
        
 (DIR) diff --git a/output/sitemap.xml b/output/sitemap.xml
       @@ -34,7 +34,7 @@
        </url>
        <url>
                <loc>https://www.codemadness.org/sfeed_curses-ui.html</loc>
       -        <lastmod>2022-05-08</lastmod>
       +        <lastmod>2025-07-24</lastmod>
        </url>
        <url>
                <loc>https://www.codemadness.org/hurl.html</loc>
 (DIR) diff --git a/pages/sfeed_curses-ui.cfg b/pages/sfeed_curses-ui.cfg
       @@ -3,4 +3,4 @@ id = sfeed_curses
        description = Sfeed_curses is a curses UI front-end for the sfeed RSS/Atom parser
        keywords = sfeed, sfeed_curses, curses, UI, front-end, RSS, atom, reader
        created = 2020-06-25
       -updated = 2022-05-08
       +updated = 2025-07-24
 (DIR) diff --git a/pages/sfeed_curses-ui.md b/pages/sfeed_curses-ui.md
       @@ -12,9 +12,9 @@ integrated in the interface itself.
        
        * Relatively few LOC, about 2.5K lines of C.
        * Few dependencies: a C compiler and a curses library (typically ncurses).
       -  It also requires a terminal (emulator) supporting UTF-8.
       +  It also requires a terminal (emulator) which supports UTF-8.
       +  * xterm-compatible shim [minicurses.h](https://git.codemadness.org/sfeed/file/minicurses.h.html)
        * Easy to customize by modifying the small source-code and shellscripts.
       -* Quite fast.
        * Plumb support: open the URL or an enclosure URL directly with any program.
        * Pipe support: pipe the selected Tab-Separated Value line to a program for
          scripting purposes. Like viewing the content in any way you like.
       @@ -61,7 +61,7 @@ $SFEED_PIPER.
        
        [![Screenshot showing the output of the pipe content script](downloads/screenshots/sfeed_curses_pipe_screenshot.png =480x270)](downloads/screenshots/sfeed_curses_pipe_screenshot.png)
        
       -The above screenshot shows the included [sfeed_content](https://git.codemadness.org/sfeed_curses/file/sfeed_content.html) shellscript which uses
       +The above screenshot shows the included [sfeed_content](https://git.codemadness.org/sfeed/file/sfeed_content.html) shellscript which uses
        the [lynx text-browser](https://invisible-island.net/lynx/) to convert HTML to plain-text.  It pipes the formatted
        plain-text to the user $PAGER (or "less").