codemadness - sfeed_tests - sfeed tests and RSS and Atom files
 (HTM) git clone git://git.codemadness.org/sfeed_tests
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       codemadness (109825B)
       ---
            1 <?xml version="1.0" encoding="UTF-8"?>
            2 <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
            3         <title type="text">Codemadness</title>
            4         <subtitle type="text">blog with various projects and articles about computer-related things</subtitle>
            5         <updated>2020-09-03T00:00:00Z</updated>
            6         <link rel="alternate" type="text/html" href="https://www.codemadness.org" />
            7         <id>https://www.codemadness.org/atom.xml</id>
            8         <link rel="self" type="application/atom+xml" href="https://www.codemadness.org/atom.xml" />
            9 <entry>
           10         <title type="text">Sfeed_curses: a curses UI front-end for sfeed</title>
           11         <link rel="alternate" type="text/html" href="https://www.codemadness.org/sfeed_curses-ui.html" />
           12         <id>https://www.codemadness.org/sfeed_curses-ui.html</id>
           13         <updated>2020-08-30T00:00:00Z</updated>
           14         <published>2020-06-25T00:00:00Z</published>
           15         <author>
           16                 <name>hiltjo</name>
           17                 <uri>https://www.codemadness.org</uri>
           18         </author>
           19         <summary type="text">Sfeed_curses is a curses UI front-end for the sfeed RSS/Atom parser</summary>
           20         <content type="html"><![CDATA[<h1>Sfeed_curses: a curses UI front-end for sfeed</h1>
           21         <p><strong>Last modification on </strong> <time>2020-08-30</time></p>
           22         <p>sfeed_curses is a curses UI front-end for <a href="sfeed.html">sfeed</a>.</p>
           23 
           24 <p>It shows the TAB-separated feed items in a graphical command-line UI.  The
           25 interface has a look inspired by the <a href="http://www.mutt.org/">mutt mail
           26 client</a>.  It has a sidebar panel for the feeds, a panel with a listing of
           27 the items and a small statusbar for the selected item/url. Some functions like
           28 searching and scrolling are integrated in the interface itself.</p>
           29 
           30 
           31 <h2>Features</h2>
           32 <ul>
           33 <li>Relatively few LOC, about 2K lines of C.</li>
           34 <li>Few dependencies: a C compiler and a curses library (typically ncurses).
           35     It also requires a terminal (emulator) supporting UTF-8.</li>
           36 <li>Easy to customize by modifying the small source-code and shellscripts.</li>
           37 <li>Quite fast.</li>
           38 <li>Plumb support: open the url or an enclosure url directly with any program.</li>
           39 <li>Pipe support: pipe the selected Tab-Separated Value line to a program for
           40     scripting purposes. Like viewing the content in any way you like.</li>
           41 <li>Yank support: copy the url or an enclosure url to the clipboard.</li>
           42 <li>Familiar keybinds: supports both vi-like, emacs-like and arrow keys for
           43     actions.</li>
           44 <li>Mouse support: xterm mouse-mode, if supported by the terminal emulator.</li>
           45 <li>Support two ways of managing read/unread items.
           46     By default sfeed_curses marks the feed items of the last day as new/bold.
           47     Alternatively a simple plain-text list with the read urls can be used.</li>
           48 </ul>
           49 
           50 
           51 <p>Like the format programs included in sfeed you can run it by giving the feed
           52 files as arguments like this:</p>
           53 <pre><code>sfeed_curses ~/.sfeed/feeds/*</code></pre>
           54 
           55 <p>... or by reading directly from stdin:</p>
           56 <pre><code>sfeed_curses &lt; ~/.sfeed/feeds/xkcd</code></pre>
           57 
           58 <p>It will show a sidebar if one or more files are specified as parameters. It will
           59 not show the sidebar by default when reading from stdin.</p>
           60 
           61 <p><a href="downloads/screenshots/sfeed_curses_screenshot.png"><img src="downloads/screenshots/sfeed_curses_screenshot.png" width="480" height="270" alt="Screenshot showing what the UI looks" loading="lazy" /></a></p>
           62 
           63 
           64 <p>On pressing the 'o' or ENTER keybind it will open the link url of an item with the plumb program.
           65 On pressing the 'a', 'e' or '@' keybind it will open the enclosure url if there is one.
           66 The default plumb program is set to "<a href="https://portland.freedesktop.org/doc/xdg-open.html">xdg-open</a>",
           67 but can be modified by setting the environment variable $SFEED_PLUMBER.
           68 The plumb program receives the url as a command-line argument.</p>
           69 
           70 
           71 <p>The TAB-Separated-Value line of the current selected item in the feed file
           72 can be piped to a program by pressing the 'c', 'p' or '|' keybind. This allows
           73 much flexibility to make a content formatter or write other custom actions or
           74 views.  This line is in the exact same format as described in the sfeed(5) man
           75 page.
           76 The pipe program can be changed by setting the environment variable $SFEED_PIPER.
           77 </p>
           78 
           79 <p><a href="downloads/screenshots/sfeed_curses_pipe_screenshot.png"><img src="downloads/screenshots/sfeed_curses_pipe_screenshot.png" width="480" height="270" alt="Screenshot showing the output of the pipe content script" loading="lazy" /></a></p>
           80 
           81 <p>The above screenshot shows the included
           82 <a href="https://git.codemadness.org/sfeed_curses/file/sfeed_content.html">sfeed_content</a>
           83 shellscript which uses the <a href="https://invisible-island.net/lynx/">lynx text-browser</a>
           84 to convert HTML to plain-text.
           85 It pipes the formatted plain-text to the user $PAGER (or "less").
           86 Of course the script can be easily changed to use a different browser like 
           87 <a href="http://w3m.sourceforge.net/">w3m</a>,
           88 <a href="http://www.jikos.cz/~mikulas/links/">links</a>, 
           89 <a href="https://www.dillo.org/">dillo</a> or 
           90 <a href="https://git.codemadness.org/webdump/file/README.html">webdump</a>.</p>
           91 
           92 <p>It's easy to modify the colorscheme by changing the macros in the source-code.
           93 On the left a <a href="https://templeos.org/">TempleOS</a>-like colorscheme on the right a <a href="https://newsboat.org/">newsboat</a>-like colorscheme.
           94 The README file contains the macros for these schemes.</p>
           95 
           96 <p><a href="downloads/screenshots/sfeed_curses_theme_screenshot.png"><img src="downloads/screenshots/sfeed_curses_theme_screenshot.png" width="480" height="270" alt="Screenshot showing a custom colorscheme" loading="lazy" /></a></p>
           97 
           98 
           99 <h2>Clone</h2>
          100 <pre><code>git clone git://<a href="//git.codemadness.org/sfeed_curses/">git.codemadness.org/sfeed_curses</a></code></pre>
          101 
          102 
          103 <h2>Download releases</h2>
          104 <p>
          105 Releases are available at:
          106 <a href="/releases/sfeed_curses/">https://codemadness.org/releases/sfeed_curses/</a>.
          107 </p>
          108 
          109 
          110 <h2>Build and install</h2>
          111 
          112 <pre><code>$ make
          113 # make install</code></pre>
          114 ]]></content>
          115 </entry>
          116 <entry>
          117         <title type="text">hurl: HTTP, HTTPS and Gopher file grabber</title>
          118         <link rel="alternate" type="text/html" href="https://www.codemadness.org/hurl.html" />
          119         <id>https://www.codemadness.org/hurl.html</id>
          120         <updated>2020-07-20T00:00:00Z</updated>
          121         <published>2019-11-10T00:00:00Z</published>
          122         <author>
          123                 <name>hiltjo</name>
          124                 <uri>https://www.codemadness.org</uri>
          125         </author>
          126         <summary type="text">hurl: HTTP, HTTPS and Gopher file grabber</summary>
          127         <content type="html"><![CDATA[<h1>hurl: HTTP, HTTPS and Gopher file grabber</h1>
          128         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
          129         <p>hurl is a relatively simple HTTP, HTTPS and Gopher client/file grabber.</p>
          130 
          131 
          132 <h2>Why?</h2>
          133 
          134 <p>Sometimes (or most of the time?) you just want to fetch a file via the HTTP,
          135 HTTPS or Gopher protocol.</p>
          136 
          137 <p>The focus of this tool is only this.</p>
          138 
          139 
          140 <h2>Features</h2>
          141 
          142 <ul>
          143 <li>Uses OpenBSD pledge(2) and unveil(2). Allow no filesystem access (writes to
          144     stdout).</li>
          145 <li>Impose time-out and maximum size limits.</li>
          146 <li>Use well-defined exitcodes for reliable scripting (curl sucks at this).</li>
          147 <li>Send as little information as possible (no User-Agent etc by default).</li>
          148 </ul>
          149 
          150 
          151 <h2>Anti-features</h2>
          152 
          153 <ul>
          154 <li>No HTTP byte range support.</li>
          155 <li>No HTTP User-Agent.</li>
          156 <li>No HTTP If-Modified-Since/If-* support.</li>
          157 <li>No HTTP auth support.</li>
          158 <li>No HTTP/2+ support.</li>
          159 <li>No HTTP keep-alive.</li>
          160 <li>No HTTP chunked-encoding support.</li>
          161 <li>No HTTP redirect support.</li>
          162 <li>No (GZIP) compression support.</li>
          163 <li>No cookie-jar or cookie parsing support.</li>
          164 <li>No Gopher text handling (".\r\n").</li>
          165 <li>... etc...</li>
          166 </ul>
          167 
          168 
          169 <h2>Dependencies</h2>
          170 
          171 <ul>
          172 <li>C compiler (C99).</li>
          173 <li>libc + some BSD functions like err() and strlcat().</li>
          174 <li>LibreSSL(-portable)</li>
          175 <li>libtls (part of LibreSSL).</li>
          176 </ul>
          177 
          178 
          179 <h2>Optional dependencies</h2>
          180 
          181 <ul>
          182 <li>POSIX make(1) (for Makefile).</li>
          183 <li>mandoc for documentation: https://mdocml.bsd.lv/</li>
          184 </ul>
          185 
          186 
          187 <h2>Clone</h2>
          188 <pre><code>git clone git://<a href="//git.codemadness.org/hurl/">git.codemadness.org/hurl</a></code></pre>
          189 
          190 
          191 <h2>Download releases</h2>
          192 <p>
          193 Releases are available at:
          194 <a href="/releases/hurl/">https://codemadness.org/releases/hurl/</a>.
          195 </p>
          196 
          197 
          198 <h2>Build and install</h2>
          199 
          200 <pre><code>$ make
          201 # make install</code></pre>
          202 
          203 
          204 <h2>Examples</h2>
          205 
          206 <p>
          207 Fetch the Atom feed from this site using a maximum filesize limit of 1MB and
          208 a time-out limit of 15 seconds:
          209 </p>
          210 
          211 <pre><code>hurl -m 1048576 -t 15 "https://codemadness.org/atom.xml"</code></pre>
          212 
          213 <p>
          214 There is an -H option to add custom headers. This way some of the anti-features
          215 listed above are supported. For example some CDNs like Cloudflare are known to block
          216 empty or certain User-Agents.
          217 </p>
          218 
          219 <p>User-Agent:</p>
          220 
          221 <pre><code>hurl -H 'User-Agent: some browser' 'https://codemadness.org/atom.xml'</code></pre>
          222 
          223 <p>HTTP Basic Auth (base64-encoded username:password):</p>
          224 
          225 <pre><code>hurl -H 'Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=' 'https://codemadness.org/atom.xml'</code></pre>
          226 
          227 <p>GZIP (this assumes the served response Content-Type is gzip):</p>
          228 
          229 <pre><code>hurl -H 'Accept-Encoding: gzip' 'https://somesite/' | gzip -d</code></pre>
          230 ]]></content>
          231 </entry>
          232 <entry>
          233         <title type="text">json2tsv: a JSON to TSV converter</title>
          234         <link rel="alternate" type="text/html" href="https://www.codemadness.org/json2tsv.html" />
          235         <id>https://www.codemadness.org/json2tsv.html</id>
          236         <updated>2020-07-20T00:00:00Z</updated>
          237         <published>2019-10-13T00:00:00Z</published>
          238         <author>
          239                 <name>hiltjo</name>
          240                 <uri>https://www.codemadness.org</uri>
          241         </author>
          242         <summary type="text">json2tsv: a JSON to TAB-Separated Value converter</summary>
          243         <content type="html"><![CDATA[<h1>json2tsv: a JSON to TSV converter</h1>
          244         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
          245         <p>
          246 json2tsv reads JSON data from stdin. It outputs each JSON type to a
          247 TAB-Separated Value format per line.
          248 </p>
          249 
          250 
          251 <h2>TAB-Separated Value format</h2>
          252 
          253 <p>The output format per line is:</p>
          254 <pre><code>nodename&lt;TAB&gt;type&lt;TAB&gt;value&lt;LF&gt;</code></pre>
          255 
          256 <p>
          257 Control-characters such as a newline, TAB and backslash (\n, \t and \\) are
          258 escaped in the nodename and value fields.  Other control-characters are
          259 removed.
          260 </p>
          261 
          262 <p>
          263 The type field is a single byte and can be:
          264 </p>
          265 
          266 <ul>
          267 <li>a for array</li>
          268 <li>b for bool</li>
          269 <li>n for number</li>
          270 <li>o for object</li>
          271 <li>s for string</li>
          272 <li>? for null</li>
          273 </ul>
          274 
          275 <p>
          276 Filtering on the first field "nodename" is easy using awk for example.
          277 </p>
          278 
          279 
          280 <h2>Features</h2>
          281 <ul>
          282 <li>Accepts all <strong>valid</strong> JSON.</li>
          283 <li>Designed to work well with existing UNIX programs like awk and grep.</li>
          284 <li>Straightforward and not much lines of code: about 475 lines of C.</li>
          285 <li>Few dependencies: C compiler (C99), libc.</li>
          286 <li>No need to learn a new (meta-)language for processing data.</li>
          287 <li>The parser supports code point decoding (\u2303) and UTF-16 surrogates (\ud83d\ude02) to UTF-8.</li>
          288 <li>It does not output control-characters to the terminal for security reasons by default (but it has a -r option if needed).</li>
          289 <li>On OpenBSD it supports <a href="https://man.openbsd.org/pledge">pledge(2)</a> for syscall restriction, pledge("stdio", NULL).</li>
          290 </ul>
          291 
          292 
          293 <h2>Cons</h2>
          294 <ul>
          295 <li>For the tool there is additional overhead by processing and filtering data
          296     from stdin after parsing.</li>
          297 <li>The parser does not do complete validation on numbers.</li>
          298 <li>The parser accepts some bad input such as invalid UTF-8
          299     (see <a href="https://tools.ietf.org/html/rfc8259#section-8.1">RFC8259 - 8.1. Character Encoding</a>).
          300     json2tsv reads from stdin and does not do assumptions about a "closed ecosystem"
          301     as described in the RFC.</li>
          302 <li>The parser accepts some bad JSON input and "extensions"
          303     (see <a href="https://tools.ietf.org/html/rfc8259#section-9">RFC8259 - 9. Parsers</a>).</li>
          304 <li>Encoded NUL bytes (\u0000) in strings are ignored.
          305     (see <a href="https://tools.ietf.org/html/rfc8259#section-9">RFC8259 - 9. Parsers</a>).
          306     "An implementation may set limits on the length and character contents of
          307     strings."</li>
          308 <li>The parser is not the fastest possible JSON parser (but also not the slowest).
          309     For example: for ease of use, at the cost of performance all strings are
          310     decoded, even though they may be unused.
          311 </li>
          312 </ul>
          313 
          314 
          315 <h2>Why Yet Another JSON parser?</h2>
          316 <p>
          317 I wanted a tool that makes parsing JSON easier and work well from the shell, similar to
          318 <a href="https://stedolan.github.io/jq/">jq</a>.
          319 </p>
          320 
          321 <p>
          322 sed and grep often work well enough for matching some value using some regex pattern,
          323 but it is not good enough to parse JSON correctly or to extract all information:
          324 just like parsing HTML/XML using some regex is not good (enough) or a good idea :P.
          325 </p>
          326 
          327 <p>
          328 I didn't want to learn a new
          329 <a href="https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions">specific meta-language which jq has</a>
          330 and wanted something simpler.
          331 While it is more efficient to embed this query language for data aggregation,
          332 it is also less simple. In my opinion it is simpler to separate this and use
          333 pattern-processing by awk or an other filtering/aggregating program.
          334 </p>
          335 
          336 <p>
          337 For the parser, there are many JSON parsers out there, like the efficient
          338 <a href="https://github.com/zserge/jsmn">jsmn parser</a>, however a few parser
          339 behaviours I want to have are:
          340 </p>
          341 
          342 <ul>
          343 <li>jsmn buffers data as tokens, which is very efficient, but also a bit
          344     annoying as an API as it requires another layer of code to interpret the
          345     tokens.</li>
          346 <li>jsmn does not handle decoding strings by default. Which is very efficient
          347     if you don't need parts of the data though.</li>
          348 <li>jsmn does not keep context of nested structures by default, so again requires
          349     writing custom utility functions for nested data.</li>
          350 </ul>
          351 
          352 <p>
          353 I went for a parser design that uses a single callback per "node" type and
          354 keeps track of the current nested structure in a single array and emits that.
          355 </p>
          356 
          357 
          358 <h2>Clone</h2>
          359 <pre><code>git clone git://<a href="//git.codemadness.org/json2tsv/">git.codemadness.org/json2tsv</a></code></pre>
          360 
          361 
          362 <h2>Download releases</h2>
          363 <p>
          364 Releases are available at:
          365 <a href="/releases/json2tsv/">https://codemadness.org/releases/json2tsv/</a>.
          366 </p>
          367 
          368 
          369 <h2>Build and install</h2>
          370 
          371 <pre><code>$ make
          372 # make install</code></pre>
          373 
          374 
          375 <h2>Examples</h2>
          376 
          377 <p>
          378 An usage example to parse posts of the JSON API of
          379 <a href="https://www.reddit.com/">reddit.com</a>
          380 and format them to a plain-text list using awk:
          381 </p>
          382 
          383 <pre><code>#!/bin/sh
          384 curl -s -H 'User-Agent:' 'https://old.reddit.com/.json?raw_json=1&amp;limit=100' | \
          385 json2tsv | \
          386 awk -F '\t' '
          387 function show() {
          388         if (length(o["title"]) == 0)
          389                 return;
          390         print n ". " o["title"] " by " o["author"] " in r/" o["subreddit"];
          391         print o["url"];
          392         print "";
          393 }
          394 $1 == ".data.children[].data" {
          395         show();
          396         n++;
          397         delete o;
          398 }
          399 $1 ~ /^\.data\.children\[\]\.data\.[a-zA-Z0-9_]*$/ {
          400         o[substr($1, 23)] = $3;
          401 }
          402 END {
          403         show();
          404 }'
          405 </code></pre>
          406 
          407 
          408 <h2>References</h2>
          409 <ul>
          410 <li>
          411         <strong>Sites:</strong>
          412         <ul>
          413         <li><a href="http://seriot.ch/parsing_json.php">seriot.ch - Parsing JSON is a Minefield</a></li>
          414         <li><a href="https://github.com/nst/JSONTestSuite">A comprehensive test suite for RFC 8259 compliant JSON parsers</a></li>
          415         <li><a href="https://json.org/">json.org</a></li>
          416         </ul>
          417 </li>
          418 <li>
          419         <strong>Current standard:</strong>
          420         <ul>
          421         <li><a href="https://tools.ietf.org/html/rfc8259">RFC8259 - The JavaScript Object Notation (JSON) Data Interchange Format</a></li>
          422         <li><a href="http://www.ecma-international.org/publications/standards/Ecma-404.htm">Standard ECMA-404 - The JSON Data Interchange Syntax (2nd edition (December 2017)</a></li>
          423         </ul>
          424 </li>
          425 <li>
          426         <strong>Historic standard:</strong>
          427         <ul>
          428         <li><a href="https://tools.ietf.org/html/rfc7159">RFC7159 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete)</a></li>
          429         <li><a href="https://tools.ietf.org/html/rfc7158">RFC7158 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete)</a></li>
          430         <li><a href="https://tools.ietf.org/html/rfc4627">RFC4627 - The JavaScript Object Notation (JSON) Data Interchange Format (obsolete, original)</a></li>
          431         </ul>
          432 </li>
          433 </ul>
          434 ]]></content>
          435 </entry>
          436 <entry>
          437         <title type="text">OpenBSD: setup a local auto-installation server</title>
          438         <link rel="alternate" type="text/html" href="https://www.codemadness.org/openbsd-autoinstall.html" />
          439         <id>https://www.codemadness.org/openbsd-autoinstall.html</id>
          440         <updated>2020-04-30T00:00:00Z</updated>
          441         <published>2019-04-24T00:00:00Z</published>
          442         <author>
          443                 <name>hiltjo</name>
          444                 <uri>https://www.codemadness.org</uri>
          445         </author>
          446         <summary type="text">OpenBSD: setup a local auto-installation server</summary>
          447         <content type="html"><![CDATA[<h1>OpenBSD: setup a local auto-installation server</h1>
          448         <p><strong>Last modification on </strong> <time>2020-04-30</time></p>
          449         <p>This guide describes how to setup a local mirror and installation/upgrade
          450 server that requires little or no input interaction.</p>
          451 
          452 
          453 <h2>Setup a local HTTP mirror</h2>
          454 <p>
          455 The HTTP mirror will be used to fetch the base sets and (optional) custom sets.
          456 In this guide we will assume <b>192.168.0.2</b> is the local installation
          457 server and mirror, the CPU architecture is amd64 and the OpenBSD release
          458 version is 6.5.  We will store the files in the directory with the structure:
          459 </p>
          460 
          461 <pre><code>http://192.168.0.2/pub/OpenBSD/6.5/amd64/</code></pre>
          462 
          463 <p>Create the www serve directory and fetch all sets and install files
          464 (if needed to save space *.iso and install65.fs can be skipped):</p>
          465 
          466 <pre><code>$ cd /var/www/htdocs
          467 $ mkdir -p pub/OpenBSD/6.5/amd64/
          468 $ cd pub/OpenBSD/6.5/amd64/
          469 $ ftp 'ftp://ftp.nluug.nl/pub/OpenBSD/6.5/amd64/*'</code></pre>
          470 
          471 <p>Verify signature and check some checksums:</p>
          472 <pre><code>$ signify -C -p /etc/signify/openbsd-65-base.pub -x SHA256.sig</code></pre>
          473 
          474 <p>Setup <a href="https://man.openbsd.org/httpd.8">httpd(8)</a> for simple file serving:</p>
          475 <pre><code># $FAVORITE_EDITOR /etc/<a href="https://man.openbsd.org/httpd.conf.5">httpd.conf</a></code></pre>
          476 
          477 <p>A minimal example config:</p>
          478 <pre><code>server "*" {
          479         listen on * port 80
          480 }</code></pre>
          481 
          482 <p>The default www root directory is: /var/www/htdocs/</p>
          483 
          484 <p>Enable the httpd daemon to start by default and start it now:</p>
          485 <pre><code># rcctl enable httpd
          486 # rcctl start httpd</code></pre>
          487 
          488 
          489 <h2>Creating an installation response/answer file</h2>
          490 <p>The installer supports loading responses to the installation/upgrade questions
          491 from a simple text file. We can do a regular installation and copy the answers from
          492 the saved file to make an automated version of it.</p>
          493 
          494 <p>Do a test installation, at the end of the installation or upgrade when asked the
          495 question:</p>
          496 <pre><code>Exit to (S)hell, (H)alt or (R)eboot?</code></pre>
          497 
          498 <p>Type S to go to the shell. Find the response file for an installation and copy it to some USB stick or
          499 write down the response answers:</p>
          500 <pre><code>cp /tmp/i/install.resp /mnt/usbstick/</code></pre>
          501 
          502 <p>A response file could be for example:</p>
          503 
          504 <pre><code>System hostname = testvm
          505 Which network interface do you wish to configure = em0
          506 IPv4 address for em0 = dhcp
          507 IPv6 address for em0 = none
          508 Which network interface do you wish to configure = done
          509 Password for root account = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.
          510 Password for user testuser = $2b$10$IqI43aXjgD55Q3nLbRakRO/UAG6SAClL9pyk0vIUpHZSAcLx8fWk.
          511 Start sshd(8) by default = no
          512 Do you expect to run the X Window System = no
          513 Setup a user = testuser
          514 Full name for user testuser = testuser
          515 What timezone are you in = Europe/Amsterdam
          516 Which disk is the root disk = wd0
          517 Use (W)hole disk MBR, whole disk (G)PT, (O)penBSD area or (E)dit = OpenBSD
          518 Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout = a
          519 Location of sets = http
          520 HTTP proxy URL = none
          521 HTTP Server = <b>192.168.0.2</b>
          522 Server directory = pub/OpenBSD/6.5/amd64
          523 Unable to connect using https. Use http instead = yes
          524 Location of sets = http
          525 Set name(s) = done
          526 Location of sets = done
          527 Exit to (S)hell, (H)alt or (R)eboot = R</code></pre>
          528 
          529 <p>Get custom encrypted password for response file:</p>
          530 <pre><code>$ printf '%s' 'yourpassword' | encrypt</code></pre>
          531 
          532 
          533 <h2>Changing the RAMDISK kernel disk image</h2>
          534 
          535 <p><a href="https://man.openbsd.org/rdsetroot.8">rdsetroot(8)</a> is publicly
          536 exposed now in base since 6.5. Before 6.5 it is available in the /usr/src/ tree as
          537 elfrdsetroot, see also the <a href="https://man.openbsd.org/rd.4">rd(4)</a> man page.</p>
          538 
          539 <pre><code>$ mkdir auto
          540 $ cd auto
          541 $ cp pubdir/bsd.rd .
          542 $ rdsetroot -x bsd.rd disk.fs
          543 # vnconfig vnd0 disk.fs
          544 # mkdir mount
          545 # mount /dev/vnd0a mount</code></pre>
          546 
          547 <p>Copy the response file (install.resp) to: mount/auto_install.conf (installation) <b>or</b>
          548 mount/auto_upgrade.conf (upgrade), but not both. In this guide we will do an
          549 auto-installation.</p>
          550 
          551 <p>Unmount, detach and patch RAMDISK:</p>
          552 <pre><code># umount mount
          553 # vnconfig -u vnd0
          554 $ rdsetroot bsd.rd disk.fs</code></pre>
          555 
          556 <p>To test copy bsd.rd to the root of some testmachine like /bsd.test.rd then
          557 (re)boot and type:</p>
          558 <pre><code>boot /bsd.test.rd</code></pre>
          559 
          560 <p>In the future (6.5+) it will be possible to copy to a file named "/bsd.upgrade" in the root of a current system
          561 and automatically load the kernel:
          562 <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">bsd.upgrade in CVS</a>
          563 ofcourse this is possible with PXE boot or some custom USB/ISO also.
          564 As explained in the <a href="https://man.openbsd.org/autoinstall.8">autoinstall(8)</a> man page:
          565 create either an auto_upgrade.conf <b>or</b> an auto_install.conf, but not both.
          566 </p>
          567 
          568 
          569 <h2>Create bootable miniroot</h2>
          570 
          571 <p>In this example the miniroot will boot the custom kernel, but fetch all the
          572 sets from the local network.</p>
          573 
          574 <p>We will base our miniroot of the official version: miniroot65.fs.</p>
          575 
          576 <p>We will create a 16MB miniroot to boot from (in this guide it is assumed the
          577 original miniroot is about 4MB and the modified kernel image fits in the new
          578 allocated space):</p>
          579 
          580 <pre><code>$ dd if=/dev/zero of=new.fs bs=512 count=32768</code></pre>
          581 
          582 <p>Copy first part of the original image to the new disk (no truncation):</p>
          583 
          584 <pre><code>$ dd conv=notrunc if=miniroot65.fs of=new.fs
          585 # vnconfig vnd0 new.fs</code></pre>
          586 
          587 
          588 <p>Expand disk OpenBSD boundaries:</p>
          589 
          590 <pre><code># disklabel -E vnd0
          591 &gt; <b>b</b>
          592 Starting sector: [1024]
          593 Size ('*' for entire disk): [8576] <b>*</b>
          594 &gt; <b>r</b>
          595 Total free sectors: 1168.
          596 &gt; <b>c a</b>
          597 Partition a is currently 8576 sectors in size, and can have a maximum
          598 size of 9744 sectors.
          599 size: [8576] <b>*</b>
          600 &gt; <b>w</b>
          601 &gt; <b>q</b></code></pre>
          602 
          603 <p>or:</p>
          604 
          605 <pre><code># printf 'b\n\n*\nc a\n*\nw\n' | disklabel -E vnd0</code></pre>
          606 
          607 
          608 <p>Grow filesystem and check it and mark as clean:</p>
          609 
          610 <pre><code># growfs -y /dev/vnd0a
          611 # fsck -y /dev/vnd0a</code></pre>
          612 
          613 
          614 <p>Mount filesystem:</p>
          615 <pre><code># mount /dev/vnd0a mount/</code></pre>
          616 
          617 <p>The kernel on the miniroot is GZIP compressed. Compress our modified bsd.rd
          618 and overwrite the original kernel:</p>
          619 
          620 <pre><code># gzip -c9n bsd.rd &gt; mount/bsd</code></pre>
          621 
          622 <p>Or to save space (+- 500KB) by stripping debug symbols, taken from bsd.gz target in
          623 <a href="https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/distrib/amd64/iso/Makefile">this Makefile</a>.</p>
          624 
          625 <pre><code>$ cp bsd.rd bsd.strip
          626 $ strip bsd.strip
          627 $ strip -R .comment -R .SUNW_ctf bsd.strip
          628 $ gzip -c9n bsd.strip &gt; bsd.gz
          629 $ cp bsd.gz mount/bsd</code></pre>
          630 
          631 
          632 <p>Now unmount and detach:</p>
          633 
          634 <pre><code># umount mount/
          635 # vnconfig -u vnd0</code></pre>
          636 
          637 <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>
          638 
          639 
          640 <h2>Adding custom sets (optional)</h2>
          641 
          642 <p>For patching <a href="https://man.openbsd.org/rc.firsttime.8">/etc/rc.firsttime</a> and other
          643 system files it is useful to use a customized installation set like siteVERSION.tgz, for example: site65.tgz.
          644 The sets can even be specified per host/MAC address like: siteVERSION-$(hostname -s).tgz so for
          645 example: site65-testvm.tgz</p>
          646 
          647 <p>When the installer checks the base sets of the mirror it looks for a file index.txt.
          648 To add custom sets the site entries have to be added.</p>
          649 
          650 <p>For example:</p>
          651 <pre><code>-rw-r--r--  1 1001  0    4538975 Oct 11 13:58:26 2018 site65-testvm.tgz</code></pre>
          652 
          653 <p>The filesize, permissions etc do not matter and are not checked by the installer.
          654    Only the filename is matched by a regular expression.</p>
          655 
          656 
          657 <h2>Sign custom site* tarball sets (optional)</h2>
          658 
          659 <p>If you have custom sets without creating a signed custom release you will be
          660 prompted for the messages:</p>
          661 <pre><code>checksum test failed</code></pre>
          662 <p>and:</p>
          663 <pre><code>unverified sets: continue without verification</code></pre>
          664 
          665 <p>OpenBSD uses the program <a href="https://man.openbsd.org/signify.1">signify(1)</a>
          666 to cryptographically sign and verify filesets.</p>
          667 
          668 <p>To create a custom public/private keypair (ofcourse make sure to store the private key privately):</p>
          669 <pre><code>$ signify -G -n -c "Custom 6.5 install" -p custom-65-base.pub -s custom-65-base.sec</code></pre>
          670 
          671 <p>Create new checksum file with filelist of the current directory (except SHA256* files):</p>
          672 <pre><code>$ printf '%s\n' * | grep -v SHA256 | xargs sha256 &gt; SHA256</code></pre>
          673 
          674 <p>Sign SHA256 and store as SHA256.sig, embed signature:</p>
          675 <pre><code>$ signify -S -e -s /privatedir/custom-65-base.sec -m SHA256 -x SHA256.sig</code></pre>
          676 
          677 <p>Verify the created signature and data is correct:</p>
          678 <pre><code>$ signify -C -p /somelocation/custom-65-base.pub -x SHA256.sig</code></pre>
          679 
          680 <p>Copy <b>only</b> the <b>public</b> key to the RAMDISK:</p>
          681 <pre><code>$ cp custom-65-base.pub mount/etc/signify/custom-65-base.pub</code></pre>
          682 
          683 <p>Now we have to patch the install.sub file to check our public key.
          684 If you know a better way without having to patch this script, please let me know.</p>
          685 
          686 <p>Change the variable PUB_KEY in the shellscript mount/install.sub from:</p>
          687 
          688 <pre><code>PUB_KEY=/etc/signify/<b>openbsd</b>-${VERSION}-base.pub</code></pre>
          689 
          690 <p>To:</p>
          691 
          692 <pre><code>PUB_KEY=/etc/signify/<b>custom</b>-${VERSION}-base.pub</code></pre>
          693 
          694 <p>And for upgrades from:</p>
          695 
          696 <pre><code>$UPGRADE_BSDRD &amp;&amp;
          697         PUB_KEY=/mnt/etc/signify/<b>openbsd</b>-$((VERSION + 1))-base.pub</code></pre>
          698 
          699 <p>To:</p>
          700 
          701 <pre><code>$UPGRADE_BSDRD &amp;&amp;
          702         PUB_KEY=/mnt/etc/signify/<b>custom</b>-$((VERSION + 1))-base.pub</code></pre>
          703 
          704 
          705 <h2>Ideas</h2>
          706 <ul>
          707 <li>Patch <a href="https://man.openbsd.org/rc.firsttime.8">rc.firsttime(8)</a>: and run syspatch, add ports, setup xenodm etc.</li>
          708 <li>Custom partitioning scheme, see <a href="https://man.openbsd.org/autoinstall.8">autoinstall(8)</a>
          709     "URL to autopartitioning template for disklabel = url".</li>
          710 <li>Setup <a href="https://man.openbsd.org/pxeboot.8">pxeboot(8)</a> to boot and install over the network using
          711     <a href="https://man.openbsd.org/dhcpd.8">dhcpd(8)</a> and <a href="https://man.openbsd.org/tftpd.8">tftpd(8)</a>
          712     then not even some USB stick is required.</li>
          713 </ul>
          714 
          715 
          716 <h2>References</h2>
          717 <ul>
          718 <li>Main OpenBSD installation and upgrade shellscript: <a href="https://cvsweb.openbsd.org/src/distrib/miniroot/install.sub">/usr/src/distrib/miniroot/install.sub</a></li>
          719 </ul>
          720 ]]></content>
          721 </entry>
          722 <entry>
          723         <title type="text">Idiotbox: Youtube interface</title>
          724         <link rel="alternate" type="text/html" href="https://www.codemadness.org/idiotbox.html" />
          725         <id>https://www.codemadness.org/idiotbox.html</id>
          726         <updated>2020-09-03T00:00:00Z</updated>
          727         <published>2019-02-10T00:00:00Z</published>
          728         <author>
          729                 <name>hiltjo</name>
          730                 <uri>https://www.codemadness.org</uri>
          731         </author>
          732         <summary type="text">Idiotbox: Youtube interface</summary>
          733         <content type="html"><![CDATA[<h1>Idiotbox: Youtube interface</h1>
          734         <p><strong>Last modification on </strong> <time>2020-09-03</time></p>
          735         <p>
          736 Idiotbox is a less resource-heavy Youtube interface.
          737 For viewing videos it is recommended to use it with
          738 <a href="https://mpv.io/">mpv</a> +
          739 <a href="https://rg3.github.io/youtube-dl/">youtube-dl</a>.
          740 </p>
          741 
          742 <p>For more (up-to-date) information see the <a href="/git/frontends/file/youtube/README.html">README</a> file.</p>
          743 
          744 
          745 <h2>Why</h2>
          746 <p>
          747 In my opinion the standard Youtube web interface is:
          748 </p>
          749 <ul>
          750         <li>Non-intuitive, too much visual crap.</li>
          751         <li>Too resource-hungry, both in CPU and bandwidth.</li>
          752         <li>Doesn't work well on simpler (text-based) browsers such as netsurf and links.</li>
          753 </ul>
          754 
          755 
          756 <h2>Features</h2>
          757 <ul>
          758         <li>Doesn't use JavaScript.</li>
          759         <li>Doesn't use (tracking) cookies.</li>
          760         <li>CSS is optional.</li>
          761         <li>Multiple interfaces available: CGI web, CLI, gopher (gph), this is a work-in-progress.</li>
          762         <li>Doesn't use or require the Google API.</li>
          763         <li>CGI interface works nice in most browsers, including text-based ones.</li>
          764         <li>On OpenBSD it runs "sandboxed" and it can be compiled as a static-linked binary with
          765             <a href="https://man.openbsd.org/pledge">pledge(2)</a>,
          766             <a href="https://man.openbsd.org/unveil">unveil(2)</a> in a chroot.</li>
          767 </ul>
          768 
          769 
          770 <h2>Cons</h2>
          771 <ul>
          772         <li>Order by upload date is incorrect (same as on Youtube).</li>
          773         <li>Some Youtube features are not supported.</li>
          774         <li>Uses scraping so might break at any point.</li>
          775 </ul>
          776 
          777 
          778 <h2>Clone</h2>
          779 <pre><code>git clone git://<a href="//git.codemadness.org/frontends/">git.codemadness.org/frontends</a></code></pre>
          780 
          781 
          782 <h2>Download releases</h2>
          783 <p>
          784 Releases are available at:
          785 <a href="/releases/frontends/">https://codemadness.org/releases/frontends/</a>.
          786 </p>
          787 
          788 
          789 <h2>View</h2>
          790 <p>
          791 <a href="https://codemadness.org/idiotbox/">You can view it here</a>.
          792 </p>
          793 
          794 <p>
          795 <a href="https://codemadness.org/idiotbox/?q=gunther+tralala">Search example</a>.
          796 </p>
          797 ]]></content>
          798 </entry>
          799 <entry>
          800         <title type="text">Gopher HTTP proxy</title>
          801         <link rel="alternate" type="text/html" href="https://www.codemadness.org/gopher-proxy.html" />
          802         <id>https://www.codemadness.org/gopher-proxy.html</id>
          803         <updated>2020-08-30T00:00:00Z</updated>
          804         <published>2018-08-17T00:00:00Z</published>
          805         <author>
          806                 <name>hiltjo</name>
          807                 <uri>https://www.codemadness.org</uri>
          808         </author>
          809         <summary type="text">Gopher HTTP proxy</summary>
          810         <content type="html"><![CDATA[<h1>Gopher HTTP proxy</h1>
          811         <p><strong>Last modification on </strong> <time>2020-08-30</time></p>
          812         <p>
          813 For fun I wrote a small HTTP Gopher proxy CGI program in C. It only supports
          814 the basic Gopher types and has some restrictions to prevent some abuse.
          815 </p>
          816 
          817 <p>
          818 For your regular Gopher browsing I recommend the simple Gopher client
          819 <a href="https://git.fifth.space/sacc/">sacc</a>.
          820 </p>
          821 
          822 <p>
          823 For more information about Gopher check out the gopherhole:
          824 <a href="http://gopherproject.org/">gopherproject.org</a>.
          825 </p>
          826 
          827 
          828 <h2>Clone</h2>
          829 <pre><code>git clone git://<a href="//git.codemadness.org/gopherproxy-c/">git.codemadness.org/gopherproxy-c</a></code></pre>
          830 
          831 
          832 <h2>View</h2>
          833 <p>
          834 <a href="https://codemadness.org/gopherproxy/">You can view it here</a>.
          835 </p>
          836 
          837 <p>
          838 <a href="/gopherproxy/?q=codemadness.org">My gopherhole using the proxy.</a>
          839 </p>
          840 ]]></content>
          841 </entry>
          842 <entry>
          843         <title type="text">Setup your own file paste service</title>
          844         <link rel="alternate" type="text/html" href="https://www.codemadness.org/paste-service.html" />
          845         <id>https://www.codemadness.org/paste-service.html</id>
          846         <updated>2018-03-10T00:00:00Z</updated>
          847         <published>2018-03-10T00:00:00Z</published>
          848         <author>
          849                 <name>hiltjo</name>
          850                 <uri>https://www.codemadness.org</uri>
          851         </author>
          852         <summary type="text">Howto setup your own secure file paste service</summary>
          853         <content type="html"><![CDATA[<h1>Setup your own file paste service</h1>
          854         <p><strong>Last modification on </strong> <time>2018-03-10</time></p>
          855         <h2 id="SSH">Setup SSH authentication</h2>
          856 
          857 <p>Make sure to setup SSH public key authentication so you don't need to enter
          858 a password each time and have a more secure authentication.</p>
          859 
          860 <p>For example in the file $HOME/.ssh/config:</p>
          861 
          862 <pre><code>Host codemadness
          863         Hostname codemadness.org
          864         Port 22
          865         IdentityFile ~/.ssh/codemadness/id_rsa
          866 </code></pre>
          867 
          868 <p>Of course also make sure to generate the private and public keys.</p>
          869 
          870 
          871 <h2 id="alias">Shell alias</h2>
          872 
          873 <p>Make an alias or function in your shell config:</p>
          874 <pre><code>pastesrv() {
          875         ssh user@codemadness "cat > /home/www/domains/codemadness.org/htdocs/paste/$1"
          876         echo "https://codemadness.org/paste/$1"
          877 }</code></pre>
          878 
          879 <p>
          880 This function reads any data from stdin and transfers the output securely via
          881 SSH and writes it to a file at the specified path. This path can be visible via
          882 HTTP, gopher or an other protocol. Then it writes the absolute url to stdout,
          883 this url can be copied to the clipboard and pasted anywhere like to an e-mail,
          884 IRC etc.
          885 </p>
          886 
          887 
          888 <h2 id="usage">Usage and examples</h2>
          889 
          890 <p>To use it, here are some examples:</p>
          891 
          892 <p>Create a patch of the last commit in the git repo and store it:</p>
          893 <pre><code>git format-patch --stdout HEAD^ | pastesrv 'somepatch.diff'</code></pre>
          894 
          895 <p>Create a screenshot of your current desktop and paste it:</p>
          896 <pre><code>xscreenshot | ff2png | pastesrv 'screenshot.png'</code></pre>
          897 
          898 <p>There are many other uses of course, use your imagination :)</p>
          899 ]]></content>
          900 </entry>
          901 <entry>
          902         <title type="text">Setup your own git hosting service</title>
          903         <link rel="alternate" type="text/html" href="https://www.codemadness.org/setup-git-hosting.html" />
          904         <id>https://www.codemadness.org/setup-git-hosting.html</id>
          905         <updated>2019-12-06T00:00:00Z</updated>
          906         <published>2018-02-25T00:00:00Z</published>
          907         <author>
          908                 <name>hiltjo</name>
          909                 <uri>https://www.codemadness.org</uri>
          910         </author>
          911         <summary type="text">Howto setup your own git hosting service</summary>
          912         <content type="html"><![CDATA[<h1>Setup your own git hosting service</h1>
          913         <p><strong>Last modification on </strong> <time>2019-12-06</time></p>
          914         <p>
          915 <strong>This article assumes you use OpenBSD for the service files and OS-specific examples.</strong>
          916 </p>
          917 
          918 
          919 <h2>Why</h2>
          920 
          921 <p>A good reason to host your own git repositories is because of having control
          922 over your own computing.
          923 Assuming your hosting is secure you can be sure noone tampers with the data.</p>
          924 
          925 <p>A particular disturbing example was
          926 <a href="https://en.wikipedia.org/wiki/SourceForge#Controversies">the SourceForge ads/malware/hijack controversies</a>.
          927 <br/>
          928 <a href="https://gitlab.com/gitlab-org/gitaly/issues/2113">As of 2019-10-23 Gitlab added telemetry to their software</a>.
          929 <a href="https://about.gitlab.com/blog/2019/10/10/update-free-software-and-telemetry/">On 2019-10-24 they reverted it again because many people complained</a>.
          930 </p>
          931 
          932 <p>The same thing can happen with Github, Bitbucket or other similar services.
          933 After all: they are just a company with commercial interests.</p>
          934 
          935 <p>Always make sure you truly own the software and can host it yourself, this will keep you
          936 in control.</p>
          937 
          938 <p>These online services also have different pricing plans and various
          939 (arbitrary) restrictions.  When you host it yourself the restrictions are the
          940 resource limits of the system and your connection, therefore it is a much more
          941 flexible solution.</p>
          942 
          943 
          944 <h2>Creating repositories</h2>
          945 
          946 <p>For the hosting it is recommended to use a so-called "bare" repository.
          947 A bare repository means no files are checked out in the folder itself.
          948 To create a bare repository use git init with the --bare argument:</p>
          949 
          950 <pre><code>$ git init --bare</code></pre>
          951 
          952 <p>I recommend to create a separate user and group for the source-code repositories.
          953 In the examples we will assume the user is called "src".</p>
          954 
          955 <p>Login as the src user and create the files. To create a directory for
          956 the repos, in this example /home/src/src:</p>
          957 
          958 <pre><code>$ mkdir -p /home/src/src
          959 $ cd /home/src/src
          960 $ git init --bare someproject
          961 $ $EDITOR someproject/description</code></pre>
          962 
          963 <p>Make sure the git-daemon process has access permissions to these repositories.</p>
          964 
          965 
          966 <h2>Install git-daemon (optional)</h2>
          967 
          968 <p>Using git-daemon you can clone the repositories publicly using the efficient
          969 git:// protocol. An alternative without having to use git-daemon is by using anonymous SSH,
          970 HTTPS or any public shared filesystem.</p>
          971 
          972 <p>When you use a private-only repository I recommend to just use SSH without
          973 git-daemon because it is secure.</p>
          974 
          975 <p>Install the git package. The package should contain "git daemon":</p>
          976 <pre><code># pkg_add git</code></pre>
          977 
          978 <p>Enable the daemon:</p>
          979 <pre><code># rcctl enable gitdaemon</code></pre>
          980 
          981 <p>Set the gitdaemon service flags to use the src directory and use all the available
          982 repositories in this directory. The command-line flags "--export-all" exports all
          983 repositories in the base path. Alternatively you can use the "git-daemon-export-ok"
          984 file (see the git-daemon man page).
          985 </p>
          986 
          987 <pre><code># rcctl set gitdaemon flags --export-all --base-path="/home/src/src"</code></pre>
          988 
          989 <p>To configure the service to run as the user _gitdaemon:</p>
          990 <pre><code># rcctl set gitdaemon user _gitdaemon</code></pre>
          991 
          992 <p>To run the daemon directly as the user _gitdaemon (without dropping priviledges from root
          993 to the user) set the following flags in /etc/rc.d/gitdaemon:</p>
          994 <pre><code>daemon_flags="--user=_gitdaemon"</code></pre>
          995 
          996 <p>Which will also avoid this warning while cloning:</p>
          997 <pre><code>"can't access /root/.git/config"</code></pre>
          998 
          999 
         1000 <p>Now start the daemon:</p>
         1001 <pre><code># rcctl start gitdaemon</code></pre>
         1002 
         1003 
         1004 <h2>Cloning and fetching changes</h2>
         1005 
         1006 <p>To test and clone the repository do:</p>
         1007 <pre><code>$ git clone git://yourdomain/someproject</code></pre>
         1008 
         1009 <p>if you skipped the optional git-daemon installation then just clone via SSH:</p>
         1010 <pre><code>$ git clone ssh://youraccount@yourdomain:/home/src/src/someproject</code></pre>
         1011 
         1012 <p>When cloning via SSH make sure to setup private/public key authentication for security
         1013         and convenience.</p>
         1014 
         1015 
         1016 <h2>Pushing changes</h2>
         1017 
         1018 <p>Add the repository as a remote:</p>
         1019 <pre><code>$ git remote add myremote ssh://youraccount@yourdomain:/home/src/src/someproject</code></pre>
         1020 
         1021 <p>Then push the changes:</p>
         1022 <pre><code>$ git push myremote master:master</code></pre>
         1023 
         1024 
         1025 <h2>Git history web browsing (optional)</h2>
         1026 
         1027 <p>Sometimes it's nice to browse the git history log of the repository in a
         1028 web browser or some other program without having to look at the local
         1029 repository.</p>
         1030 
         1031 <ul>
         1032         <li><a href="stagit.html">Stagit</a> is a static HTML page generator for git.</li>
         1033         <li><a href="stagit-gopher.html">Stagit-gopher</a> is a static page generator for
         1034                 <a href="http://gopherproject.org/">gopher</a> and
         1035                 <a href="gopher://bitreich.org/1/scm/geomyidae">geomyidae</a>.</li>
         1036         <li>cgit is a CGI-based program which shows HTML views of your repository,
         1037                 see also the page: <a href="openbsd-httpd-and-cgit.html">OpenBSD httpd, slowcgi and cgit</a>.</li>
         1038 </ul>
         1039 
         1040 <p>It's also possible with these tools to generate an Atom feed and then use a RSS/Atom reader
         1041 to track the git history:</p>
         1042 
         1043 <ul>
         1044         <li>An example url from cgit:
         1045         <a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/">Linux kernel tree</a>.</li>
         1046 
         1047         <li>An example url from stagit:
         1048         <a href="//git.codemadness.org/www.codemadness.org/atom.xml">www.codemadness.org</a>.</li>
         1049 </ul>
         1050 
         1051 <p>
         1052 My <a href="sfeed-simple-feed-parser.html">sfeed</a> program can be used as a RSS/Atom reader.
         1053 </p>
         1054 
         1055 
         1056 <h2>Setting up git hooks (optional)</h2>
         1057 
         1058 <p>
         1059 Using git hooks you can setup automated triggers, for example when pushing to a repository.
         1060 Some useful examples can be:
         1061 </p>
         1062 
         1063 <ul>
         1064         <li><a href="/git/stagit/file/example_post-receive.sh.html">For
         1065                 stagit: update the repo files (example post-receive hook).</a></li>
         1066         <li>Send an e-mail with the commit subject and message.</li>
         1067         <li>Log/notify commits and changes to an IRC channel using
         1068                 <a href="https://tools.suckless.org/ii/">ii</a>.</li>
         1069         <li>Create a release tarball and checksum file on a tag push/change.</li>
         1070         <li>Checkout files for website content.</li>
         1071 </ul>
         1072 
         1073 
         1074 <p>I hope this is useful. Have fun.</p>
         1075 ]]></content>
         1076 </entry>
         1077 <entry>
         1078         <title type="text">Setup an OpenBSD SPARC64 VM in QEMU</title>
         1079         <link rel="alternate" type="text/html" href="https://www.codemadness.org/openbsd-sparc64-vm.html" />
         1080         <id>https://www.codemadness.org/openbsd-sparc64-vm.html</id>
         1081         <updated>2020-04-18T00:00:00Z</updated>
         1082         <published>2017-12-11T00:00:00Z</published>
         1083         <author>
         1084                 <name>hiltjo</name>
         1085                 <uri>https://www.codemadness.org</uri>
         1086         </author>
         1087         <summary type="text">Setup an OpenBSD SPARC64 VM in QEMU</summary>
         1088         <content type="html"><![CDATA[<h1>Setup an OpenBSD SPARC64 VM in QEMU</h1>
         1089         <p><strong>Last modification on </strong> <time>2020-04-18</time></p>
         1090         <p>This describes how to setup an OpenBSD SPARC64 VM in QEMU.</p>
         1091 
         1092 
         1093 <h2>Create a disk image</h2>
         1094 <p>To create a 5GB disk image:</p>
         1095 <pre><code>qemu-img create -f qcow2 fs.qcow2 5G</code></pre>
         1096 
         1097 
         1098 <h2>Install</h2>
         1099 <p>In this guide we'll use the installation ISO to install OpenBSD. Make sure
         1100 to download the latest (stable) OpenBSD ISO, for example install62.iso.</p>
         1101 
         1102 <ul>
         1103         <li>Change -boot c to -boot d to boot from the CD-ROM and do a clean install.</li>
         1104         <li>Change -cdrom install62.iso to the location of your ISO file.</li>
         1105         <li>When the install is done type: halt -p</li>
         1106         <li>Change -boot d back to -boot c.</li>
         1107 </ul>
         1108 
         1109 <p>Start the VM:</p>
         1110 
         1111 <pre><code>#!/bin/sh
         1112 LC_ALL=C QEMU_AUDIO_DRV=none \
         1113 qemu-system-sparc64 \
         1114         -machine sun4u,usb=off \
         1115         -realtime mlock=off \
         1116         -smp 1,sockets=1,cores=1,threads=1 \
         1117         -rtc base=utc \
         1118         -m 1024 \
         1119         -boot c \
         1120         -drive file=fs.qcow2,if=none,id=drive-ide0-0-1,format=qcow2,cache=none \
         1121         -cdrom install62.iso \
         1122         -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-1,id=ide0-0-1 \
         1123         -msg timestamp=on \
         1124         -serial pty -nographic \
         1125         -net nic,model=ne2k_pci -net user
         1126 </code></pre>
         1127 
         1128 <p>The VM has the following properties:</p>
         1129 <ul>
         1130 <li>No audio.</li>
         1131 <li>No USB.</li>
         1132 <li>No VGA graphics: serial console.</li>
         1133 <li>Netdev is ne0 (Realtek 8029).</li>
         1134 <li>1024MB memory.</li>
         1135 </ul>
         1136 
         1137 <p>From your host connect to the serial device indicated by QEMU, for example:</p>
         1138 <pre><code>(qemu) 2017-11-19T15:14:20.884312Z qemu-system-sparc64: -serial pty: char device redirected to <strong>/dev/ttyp0</strong> (label serial0)</code></pre>
         1139 
         1140 <p>Then you can use the serial terminal emulator <strong>cu</strong> to attach:</p>
         1141 <pre><code>cu -l <strong>/dev/ttyp0</strong></code></pre>
         1142 
         1143 <p>Another option could be using the <a href="https://git.suckless.org/st/">simple terminal (st)</a> from <a href="https://suckless.org/">suckless</a>:</p>
         1144 <pre><code>st -l <strong>/dev/ttyp0</strong></code></pre>
         1145 
         1146 <p>using cu to detach the <a href="https://man.openbsd.org/cu#~^D">cu(1) man page</a> says:</p>
         1147 
         1148 <pre><code>Typed characters are normally transmitted directly to the remote machine (which
         1149 does the echoing as well).  A tilde ('~') appearing as the first character of a
         1150 line is an escape signal; the following are recognized:
         1151 
         1152     ~^D or ~.  Drop the connection and exit.  Only the connection is
         1153                the login session is not terminated.</code></pre>
         1154 
         1155 <p>On boot you have to type:</p>
         1156 
         1157 <pre><code>root device: <strong>wd0a</strong>
         1158 for swap use the default (wd0b) <strong>Press enter</strong></code></pre>
         1159 
         1160 
         1161 <h2>Initial settings on first boot (optional)</h2>
         1162 
         1163 <p>Automatic network configuration using DHCP</p>
         1164 <pre><code>echo "dhcp" > /etc/hostname.ne0</code></pre>
         1165 
         1166 <p>To bring up the interface (will be automatic on the next boot):</p>
         1167 <pre><code>sh /etc/netstart</code></pre>
         1168 
         1169 <p>Add a mirror to /etc/installurl for package installation. Make sure to lookup
         1170 the most efficient/nearby mirror site on the OpenBSD mirror page.</p>
         1171 <pre><code>echo "https://ftp.hostserver.de/pub/OpenBSD" > /etc/installurl</code></pre>
         1172 
         1173 
         1174 <p>I hope this is useful. Have fun.</p>
         1175 ]]></content>
         1176 </entry>
         1177 <entry>
         1178         <title type="text">Tscrape: a Twitter scraper</title>
         1179         <link rel="alternate" type="text/html" href="https://www.codemadness.org/tscrape.html" />
         1180         <id>https://www.codemadness.org/tscrape.html</id>
         1181         <updated>2020-07-20T00:00:00Z</updated>
         1182         <published>2017-09-24T00:00:00Z</published>
         1183         <author>
         1184                 <name>hiltjo</name>
         1185                 <uri>https://www.codemadness.org</uri>
         1186         </author>
         1187         <summary type="text">Tscrape: a Twitter scraper</summary>
         1188         <content type="html"><![CDATA[<h1>Tscrape: a Twitter scraper</h1>
         1189         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
         1190         <p>Tscrape is a Twitter web scraper and archiver.</p>
         1191 
         1192 <p>Twitter removed the functionality to follow users using a RSS feed without
         1193 authenticating or using their API. With this program you can format tweets in
         1194 any way you like relatively anonymously.</p>
         1195 
         1196 <p>For more (up-to-date) information see the <a href="/git/tscrape/file/README.html">README</a> file.</p>
         1197 
         1198 
         1199 <h2>Clone</h2>
         1200 <pre><code>git clone git://<a href="//git.codemadness.org/tscrape/">git.codemadness.org/tscrape</a></code></pre>
         1201 
         1202 
         1203 <h2>Download releases</h2>
         1204 <p>
         1205 Releases are available at:
         1206 <a href="/releases/tscrape/">https://codemadness.org/releases/tscrape/</a>.
         1207 </p>
         1208 
         1209 
         1210 <h2>Examples</h2>
         1211 <p>Output format examples</p>
         1212 
         1213 <ul>
         1214 <li><a href="tscrape/tscrape_html.html">tscrape_html: HTML</a></li>
         1215 <li><a href="tscrape/tscrape_plain.txt">tscrape_plain: Text</a></li>
         1216 </ul>
         1217 ]]></content>
         1218 </entry>
         1219 <entry>
         1220         <title type="text">jsdatatable: a small datatable Javascript</title>
         1221         <link rel="alternate" type="text/html" href="https://www.codemadness.org/datatable.html" />
         1222         <id>https://www.codemadness.org/datatable.html</id>
         1223         <updated>2020-07-20T00:00:00Z</updated>
         1224         <published>2017-09-24T00:00:00Z</published>
         1225         <author>
         1226                 <name>hiltjo</name>
         1227                 <uri>https://www.codemadness.org</uri>
         1228         </author>
         1229         <summary type="text">jsdatatable: a small datatable Javascript</summary>
         1230         <content type="html"><![CDATA[<h1>jsdatatable: a small datatable Javascript</h1>
         1231         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
         1232         <p>This is a small datatable Javascript with no dependencies.</p>
         1233 
         1234 
         1235 <h2>Features</h2>
         1236 
         1237 <ul>
         1238 <li>Small:
         1239         <ul>
         1240                 <li>Filesize: +- 9.1KB.</li>
         1241                 <li>Lines: +- 300, not much code, so hopefully easy to understand.</li>
         1242                 <li>No dependencies on other libraries like jQuery.</li>
         1243         </ul>
         1244 </li>
         1245 <li>Sorting on columns, multi-column support with shift-click.</li>
         1246 <li>Filtering values: case-insensitively, tokenized (separated by space).</li>
         1247 <li>Able to add custom filtering, parsing and sorting functions.</li>
         1248 <li>Helper function for delayed (150ms) filtering, so filtering feels more
         1249     responsive for big datasets.</li>
         1250 <li>Permissive ISC license, see LICENSE file.</li>
         1251 <li>"Lazy scroll" mode:
         1252         <ul>
         1253                 <li>fixed column headers and renders only visible rows, this allows you to
         1254                     "lazily" render millions of rows.</li>
         1255         </ul>
         1256 </li>
         1257 <li>Officially supported browsers are:
         1258         <ul>
         1259                 <li>Firefox and Firefox ESR.</li>
         1260                 <li>Chrome and most recent webkit-based browsers.</li>
         1261                 <li>IE10+.</li>
         1262         </ul>
         1263 </li>
         1264 </ul>
         1265 
         1266 
         1267 <h2>Why? and a comparison</h2>
         1268 
         1269 <p>
         1270 It was created because all the other datatable scripts suck balls.
         1271 </p>
         1272 
         1273 <p>
         1274 Most Javascripts nowadays have a default dependency on jQuery, Bootstrap or other frameworks.
         1275 </p>
         1276 
         1277 <p>
         1278 jQuery adds about 97KB and Bootstrap adds about 100KB to your scripts and CSS as a dependency.
         1279 This increases the CPU, memory and bandwidth consumption and latency. It also adds
         1280 complexity to your scripts.
         1281 </p>
         1282 
         1283 <p>
         1284 jQuery was mostly used for backwards-compatibility in the Internet Explorer days, but is
         1285 most often not needed anymore. It contains functionality to query the DOM using CSS-like
         1286 selectors, but this is now supported with for example document.querySelectorAll.
         1287 Functionality like a JSON parser is standard available now: JSON.parse().
         1288 </p>
         1289 
         1290 
         1291 <h3>Size comparison</h3>
         1292 
         1293 <p>All sizes are not "minified" or gzipped.</p>
         1294 
         1295 <table class="datatable">
         1296 <thead>
         1297 <tr>
         1298         <th>Name</th>
         1299         <th class="a-r" data-parse="int">Total</th>
         1300         <th class="a-r" data-parse="int">JS</th>
         1301         <th class="a-r" data-parse="int">CSS</th>
         1302         <th class="a-r" data-parse="int">Images</th>
         1303         <th class="a-r" data-parse="int">jQuery</th>
         1304 </tr>
         1305 </thead>
         1306 <tbody>
         1307 <tr>
         1308         <td><a href="/git/jscancer/">jsdatatable</a></td>
         1309         <td class="a-r g" data-value="12900">12.9KB</td>
         1310         <td class="a-r g" data-value="9100">9.1KB</td>
         1311         <td class="a-r g" data-value="2500">2.5KB</td>
         1312         <td class="a-r g" data-value="1300">1.3KB</td>
         1313         <td class="a-r g" data-value="0">-</td>
         1314 </tr>
         1315 <tr>
         1316         <td><a href="https://datatables.net/">datatables.net</a> (without plugins)</td>
         1317         <td class="a-r r" data-value="563400">563.4KB</td>
         1318         <td class="a-r r" data-value="449300">449.3KB</td>
         1319         <td class="a-r r" data-value="16000">16KB</td>
         1320         <td class="a-r g" data-value="800">0.8KB</td>
         1321         <td class="a-r r" data-value="97300">97.3KB</td>
         1322 </tr>
         1323 <tr>
         1324         <td><a href="https://plugins.jquery.com/jdatatable/">jdatatable</a></td>
         1325         <td class="a-r r" data-value="154600">154.6KB</td>
         1326         <td class="a-r r" data-value="53000">53KB</td>
         1327         <td class="a-r g" data-value="1000">1KB</td>
         1328         <td class="a-r g" data-value="3300">3.3KB</td>
         1329         <td class="a-r r" data-value="97300">97.3KB</td>
         1330 </tr>
         1331 </tbody>
         1332 </table>
         1333 
         1334 <p>
         1335 Of course jsdatatable has less features (less is more!), but it does 90% of what's needed.
         1336 Because it is so small it is also much simpler understand and extend with required features
         1337 if needed.
         1338 </p>
         1339 
         1340 <p>
         1341 See also: <a href="http://idlewords.com/talks/website_obesity.htm">The website obesity crisis</a>
         1342 </p>
         1343 
         1344 
         1345 <h2>Clone</h2>
         1346 
         1347 <pre><code>git clone git://<a href="//git.codemadness.org/jscancer/">git.codemadness.org/jscancer</a></code></pre>
         1348 <p>
         1349 It is in the datatable directory.
         1350 </p>
         1351 
         1352 
         1353 <h2>Download releases</h2>
         1354 <p>
         1355 Releases are available at:
         1356 <a href="/releases/jscancer/">https://codemadness.org/releases/jscancer/</a>.
         1357 </p>
         1358 
         1359 
         1360 <h2>Usage</h2>
         1361 
         1362 <h3>Examples</h3>
         1363 
         1364 <p>
         1365 See example.html for an example. A stylesheet file datatable.css is also
         1366 included, it contains the icons as embedded images.
         1367 </p>
         1368 
         1369 <p>
         1370 A table should have the classname "datatable" set, it must contain a &lt;thead&gt;
         1371 for the column headers (&lt;td&gt; or &lt;th&gt;) and &lt;tbody&gt; element for the data. The
         1372 minimal code needed for a working datatable:
         1373 </p>
         1374 
         1375 <pre><code>&lt;html&gt;
         1376 &lt;body&gt;
         1377 &lt;input class="filter-text" /&gt;&lt;!-- optional --&gt;
         1378 &lt;table class="datatable"&gt;
         1379         &lt;thead&gt;&lt;!-- columns --&gt;
         1380                 &lt;tr&gt;&lt;td&gt;Click me&lt;/td&gt;&lt;/tr&gt;
         1381         &lt;/thead&gt;
         1382         &lt;tbody&gt;&lt;!-- data --&gt;
         1383                 &lt;tr&gt;&lt;td&gt;a&lt;/td&gt;&lt;/tr&gt;
         1384                 &lt;tr&gt;&lt;td&gt;b&lt;/td&gt;&lt;/tr&gt;
         1385         &lt;/tbody&gt;
         1386 &lt;/table&gt;
         1387 &lt;script type="text/javascript" src="datatable.js"&gt;&lt;/script&gt;
         1388 &lt;script type="text/javascript"&gt;var datatables = datatable_autoload();&lt;/script&gt;
         1389 &lt;/body&gt;
         1390 &lt;/html&gt;
         1391 </code></pre>
         1392 
         1393 
         1394 <h3>Column attributes</h3>
         1395 
         1396 <p>
         1397 The following column attributes are supported:
         1398 </p>
         1399 
         1400 <table class="datatable">
         1401 <thead>
         1402 <tr>
         1403         <th>Attribute name</th>
         1404         <th>Description</th>
         1405 </tr>
         1406 </thead>
         1407 <tbody>
         1408 <tr>
         1409         <td>data-filterable</td>
         1410         <td>If "1" or "true" specifies if the column can be filtered,
         1411                       default: "true".</td>
         1412 </tr>
         1413 <tr>
         1414         <td>data-parse</td>
         1415         <td>Specifies how to parse the values, default: "string",
         1416             which is datatable_parse_string(). See PARSING section
         1417             below.</td>
         1418 </tr>
         1419 <tr>
         1420         <td>data-sort</td>
         1421         <td>Specifies how to sort the values: default: "default",
         1422             which is datatable_sort_default(). See SORTING section
         1423             below.</td>
         1424 </tr>
         1425 <tr>
         1426         <td>data-sortable</td>
         1427         <td>If "1" or "true" specifies if the column can be sorted,
         1428             default: "true".</td>
         1429 </tr>
         1430 </tbody>
         1431 </table>
         1432 
         1433 
         1434 <h3>Parsing</h3>
         1435 
         1436 <p>
         1437 By default only parsing for the types: date, float, int and string are
         1438 supported, but other types can be easily added as a function with the name:
         1439 datatable_parse_&lt;typename&gt;(). The parse functions parse the data-value
         1440 attribute when set or else the cell content (in order). Because of this
         1441 behaviour you can set the actual values as the data-value attribute and use
         1442 the cell content for display. This is useful to display and properly sort
         1443 locale-aware currency, datetimes etc.
         1444 </p>
         1445 
         1446 
         1447 <h3>Filtering</h3>
         1448 
         1449 <p>
         1450 Filtering will be done case-insensitively on the cell content and when set also
         1451 on the data-value attribute. The filter string is split up as tokens separated
         1452 by space. Each token must match atleast once per row to display it.
         1453 </p>
         1454 
         1455 
         1456 <h3>Sorting</h3>
         1457 
         1458 <p>
         1459 Sorting is done on the parsed values by default with the function:
         1460 datatable_sort_default(). To change this you can set a customname string on
         1461 the data-sort attribute on the column which translates to the function:
         1462 datatable_sort_&lt;customname&gt;().
         1463 </p>
         1464 
         1465 <p>
         1466 In some applications locale values are used, like for currency, decimal numbers
         1467 datetimes. Some people also like to use icons or extended HTML elements inside
         1468 the cell. Because jsdatatable sorts on the parsed value (see section PARSING)
         1469 it is possible to sort on the data-value attribute values and use the cell
         1470 content for display.
         1471 </p>
         1472 
         1473 <p>For example:</p>
         1474 
         1475 <p>
         1476 currency, decimal numbers:
         1477         use data-value attribute with floating-point number, set data-parse
         1478         column to "float".
         1479 date/datetimes:
         1480         use data-value attribute with UNIX timestamps (type int), set
         1481         data-parse on column to "int" or set the data-parse attribute on
         1482         column to "date" which is datatable_parse_date(), then make sure to
         1483         use Zulu times, like: "2016-01-01T01:02:03Z" or other
         1484         time strings that are parsable as the data-value attribute.
         1485 icons:
         1486         generally use data-value attribute with integer as weight value to sort
         1487         on, set data-parse column to "int".
         1488 </p>
         1489 
         1490 
         1491 <h3>Dynamically update data</h3>
         1492 <p>
         1493 To update data dynamically see example-ajax.html for an example how to do this.
         1494 </p>
         1495 
         1496 
         1497 <h3>Caveats</h3>
         1498 <ul>
         1499 <li>A date, integer, float or other values must be able to parse properly, when
         1500   the parse function returns NaN, null or undefined etc. the sorting behaviour
         1501   is also undefined. It is recommended to always set a zero value for each
         1502   type.</li>
         1503 <li>&lt;tfoot&gt; is not supported in datatables in "lazy" mode.</li>
         1504 </ul>
         1505 
         1506 
         1507 <h2>Demo / example</h2>
         1508 
         1509 <noscript>
         1510 <p>
         1511 <strong>For the below example to work you need to have Javascript enabled.</strong>
         1512 </p>
         1513 </noscript>
         1514 
         1515 <p>
         1516 <a href="datatable-example.html">datatable-example.html</a>
         1517 </p>
         1518 
         1519 <link rel="stylesheet" type="text/css" href="datatable.css" />
         1520 <style type="text/css">
         1521         th        { text-align: left;  }
         1522         .a-r      { text-align: right; }
         1523         .no-stock { background-color: #ffcccc !important; }
         1524         .r { background-color: #ffcccc !important; }
         1525         .g { background-color: #ccffcc !important; }
         1526 
         1527 /*        @media (prefers-color-scheme: dark) {
         1528                 .r { background-color: #700 !important; }
         1529                 .g { background-color: #070 !important; }
         1530         }*/
         1531 </style>
         1532 ]]></content>
         1533 </entry>
         1534 <entry>
         1535         <title type="text">Stagit-gopher: a static git page generator for gopher</title>
         1536         <link rel="alternate" type="text/html" href="https://www.codemadness.org/stagit-gopher.html" />
         1537         <id>https://www.codemadness.org/stagit-gopher.html</id>
         1538         <updated>2020-07-20T00:00:00Z</updated>
         1539         <published>2017-08-04T00:00:00Z</published>
         1540         <author>
         1541                 <name>hiltjo</name>
         1542                 <uri>https://www.codemadness.org</uri>
         1543         </author>
         1544         <summary type="text">a static git page generator for gopher</summary>
         1545         <content type="html"><![CDATA[<h1>Stagit-gopher: a static git page generator for gopher</h1>
         1546         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
         1547         <p>
         1548 stagit-gopher is a static page generator for Gopher.
         1549 It creates the pages as static <a href="http://git.r-36.net/geomyidae/">geomyidae</a> .gph files.
         1550 stagit-gopher is a modified version from the HTML version of stagit.
         1551 </p>
         1552 
         1553 <p>
         1554 <a href="/git/stagit-gopher/file/README.html">Read the README for more information about it</a>.
         1555 </p>
         1556 
         1557 <p>
         1558 I also run a gopherhole and stagit-gopher, you can see how it looks here:
         1559 <a href="gopher://codemadness.org/">gopher://codemadness.org/</a>.
         1560 </p>
         1561 
         1562 <p>
         1563 <a href="https://git.fifth.space/sacc/log.html">sacc</a> is a good Gopher client to view it.
         1564 </p>
         1565 
         1566 
         1567 <h2>Features</h2>
         1568 <ul>
         1569 <li>Log of all commits from HEAD.</li>
         1570 <li>Log and diffstat per commit.</li>
         1571 <li>Show file tree with line numbers.</li>
         1572 <li>Show references: local branches and tags.</li>
         1573 <li>Detect README and LICENSE file from HEAD and link it as a webpage.</li>
         1574 <li>Detect submodules (.gitmodules file) from HEAD and link it as a webpage.</li>
         1575 <li>Atom feed log (atom.xml).</li>
         1576 <li>Make index page for multiple repositories with stagit-gopher-index.</li>
         1577 <li>After generating the pages (relatively slow) serving the files is very fast,
         1578     simple and requires little resources (because the content is static), a
         1579     <a href="http://git.r-36.net/geomyidae/">geomyidae</a> Gopher server is required.</li>
         1580 <li>Security: all pages are static. No CGI or dynamic code is run for the interface.
         1581     Using it with a secure Gopher server such as
         1582     <a href="http://git.r-36.net/geomyidae/">geomyidae</a> it is privilege-dropped and chroot(2)'d.</li>
         1583 <li>Simple to setup: the content generation is clearly separated from serving it. This makes configuration as simple as copying a few directories
         1584     and scripts.</li>
         1585 <li>Usable with Gopher clients such as lynx and
         1586     <a href="https://git.fifth.space/sacc/log.html">sacc</a>.
         1587 </li>
         1588 </ul>
         1589 
         1590 
         1591 <h2>Cons</h2>
         1592 <ul>
         1593 <li>Not suitable for large repositories (2000+ commits), because diffstats are
         1594     an expensive operation, the cache (-c flag) is a workaround for this in
         1595     some cases.</li>
         1596 <li>Not suitable for large repositories with many files, because all files are
         1597     written for each execution of stagit. This is because stagit shows the lines
         1598     of textfiles and there is no "cache" for file metadata (this would add more
         1599     complexity to the code).</li>
         1600 <li>Not suitable for repositories with many branches, a quite linear history is
         1601     assumed (from HEAD).</li>
         1602 <li>Relatively slow to run the first time (about 3 seconds for sbase,
         1603     1500+ commits), incremental updates are faster.</li>
         1604 <li>Does not support some of the dynamic features cgit has (for HTTP), like:
         1605         <ul>
         1606         <li>Snapshot tarballs per commit.</li>
         1607         <li>File tree per commit.</li>
         1608         <li>History log of branches diverged from HEAD.</li>
         1609         <li>Stats (git shortlog -s).</li>
         1610         </ul>
         1611 </li>
         1612 </ul>
         1613 
         1614 <p>This is by design, just use git locally.</p>
         1615 
         1616 
         1617 <h2>Clone</h2>
         1618 <pre><code>git clone git://<a href="//git.codemadness.org/stagit-gopher/">git.codemadness.org/stagit-gopher</a></code></pre>
         1619 
         1620 
         1621 <h2>Download releases</h2>
         1622 <p>Releases are available at:
         1623 
         1624 <a href="/releases/stagit-gopher/">https://codemadness.org/releases/stagit-gopher/</a>
         1625 and
         1626 <a href="https://dl.2f30.org/releases/">https://dl.2f30.org/releases/</a>stagit-gopher-*.tar.gz</p>
         1627 ]]></content>
         1628 </entry>
         1629 <entry>
         1630         <title type="text">Saait: a boring HTML page generator</title>
         1631         <link rel="alternate" type="text/html" href="https://www.codemadness.org/saait.html" />
         1632         <id>https://www.codemadness.org/saait.html</id>
         1633         <updated>2020-07-20T00:00:00Z</updated>
         1634         <published>2017-06-10T00:00:00Z</published>
         1635         <author>
         1636                 <name>hiltjo</name>
         1637                 <uri>https://www.codemadness.org</uri>
         1638         </author>
         1639         <summary type="text">Saait: a boring HTML page generator</summary>
         1640         <content type="html"><![CDATA[<h1>Saait: a boring HTML page generator</h1>
         1641         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
         1642         <p>Saait is the most boring static HTML page generator.</p>
         1643 
         1644 <p>Meaning of saai (dutch): boring. Pronunciation: site</p>
         1645 
         1646 <p><a href="/git/saait/file/README.html">Read the README for more information about it</a>.</p>
         1647 
         1648 <p>
         1649 I used to use <a href="/git/static-site-scripts/files.html">shellscripts</a> to generate the static pages,
         1650 but realised I wanted a small program that works on each platform consistently.
         1651 There are many incompatibilities or unimplemented features in base tools across different platforms: Linux, UNIX, Windows.
         1652 </p>
         1653 
         1654 <p>This site is created using saait.</p>
         1655 
         1656 
         1657 <h2>Features</h2>
         1658 <ul>
         1659 <li>Single small binary that handles all the things. At run-time no dependency on other tools.</li>
         1660 <li>Few lines of code (about 575 lines of C) and no dependencies except: a C compiler and libc.</li>
         1661 <li>Works on most platforms: tested on Linux, *BSD, Windows.</li>
         1662 <li>Simple template syntax.</li>
         1663 <li>Uses HTML output by default, but can easily be modified to generate any textual content, like gopher pages, wiki pages or other kinds of documents.</li>
         1664 <li>Out-of-the-box supports: creating an index page of all pages, Atom feed, twtxt.txt feed, sitemap.xml and urllist.txt.</li>
         1665 </ul>
         1666 
         1667 
         1668 <h2>Cons</h2>
         1669 <ul>
         1670 <li>Simple template syntax, but very basic. Requires C knowledge to extend it if needed.</li>
         1671 <li>Only basic (no nested) template blocks supported.</li>
         1672 </ul>
         1673 
         1674 
         1675 <h2>Clone</h2>
         1676 <pre><code>git clone git://<a href="//git.codemadness.org/saait/">git.codemadness.org/saait</a></code></pre>
         1677 
         1678 
         1679 <h2>Download releases</h2>
         1680 <p>
         1681 Releases are available at:
         1682 <a href="/releases/saait/">https://codemadness.org/releases/saait/</a>.
         1683 </p>
         1684 
         1685 
         1686 <h2>Documentation / man page</h2>
         1687 <p>
         1688 Below is the saait(1) man page, which includes usage examples.
         1689 </p>
         1690 
         1691 <pre><code>SAAIT(1)                    General Commands Manual                      SAAIT(1)
         1692 
         1693 NAME
         1694      saait  the most boring static page generator
         1695 
         1696 SYNOPSIS
         1697      saait [-c configfile] [-o outputdir] [-t templatesdir] pages...
         1698 
         1699 DESCRIPTION
         1700      saait writes HTML pages to the output directory.
         1701 
         1702      The arguments pages are page config files, which are processed in the
         1703      given order.
         1704 
         1705      The options are as follows:
         1706 
         1707      -c configfile
         1708              The global configuration file, the default is &quot;config.cfg&quot;.  Each
         1709              page configuration file inherits variables from this file.         These
         1710              variables can be overwritten per page.
         1711 
         1712      -o outputdir
         1713              The output directory, the default is &quot;output&quot;.
         1714 
         1715      -t templatesdir
         1716              The templates directory, the default is &quot;templates&quot;.
         1717 
         1718 DIRECTORY AND FILE STRUCTURE
         1719      A recommended directory structure for pages, although the names can be
         1720      anything:
         1721      pages/001-page.cfg
         1722      pages/001-page.html
         1723      pages/002-page.cfg
         1724      pages/002-page.html
         1725 
         1726      The directory and file structure for templates must be:
         1727      templates/&lt;templatename&gt;/header.ext
         1728      templates/&lt;templatename&gt;/item.ext
         1729      templates/&lt;templatename&gt;/footer.ext
         1730 
         1731      The following filename prefixes are detected for template blocks and
         1732      processed in this order:
         1733 
         1734      &quot;header.&quot;
         1735              Header block.
         1736 
         1737      &quot;item.&quot;
         1738              Item block.
         1739 
         1740      &quot;footer.&quot;
         1741              Footer block.
         1742 
         1743      The files are saved as output/&lt;templatename&gt;, for example
         1744      templates/atom.xml/* will become: output/atom.xml.         If a template block
         1745      file does not exist then it is treated as if it was empty.
         1746 
         1747      Template directories starting with a dot (&quot;.&quot;) are ignored.
         1748 
         1749      The &quot;page&quot; templatename is special and will be used per page.
         1750 
         1751 CONFIG FILE
         1752      A config file has a simple key=value configuration syntax, for example:
         1753 
         1754      # this is a comment line.
         1755      filename = example.html
         1756      title = Example page
         1757      description = This is an example page
         1758      created = 2009-04-12
         1759      updated = 2009-04-14
         1760 
         1761      The following variable names are special with their respective defaults:
         1762 
         1763      contentfile
         1764              Path to the input content filename, by default this is the path
         1765              of the config file with the last extension replaced to &quot;.html&quot;.
         1766 
         1767      filename
         1768              The filename or relative file path for the output file for this
         1769              page.  By default the value is the basename of the contentfile.
         1770              The path of the written output file is the value of filename
         1771              appended to the outputdir path.
         1772 
         1773      A line starting with # is a comment and is ignored.
         1774 
         1775      TABs and spaces before and after a variable name are ignored.  TABs and
         1776      spaces before a value are ignored.
         1777 
         1778 TEMPLATES
         1779      A template (block) is text.  Variables are replaced with the values set
         1780      in the config files.
         1781 
         1782      The possible operators for variables are:
         1783 
         1784      $             Escapes a XML string, for example: &lt; to the entity &amp;lt;.
         1785 
         1786      #             Literal raw string value.
         1787 
         1788      %             Insert contents of file of the value of the variable.
         1789 
         1790      For example in a HTML item template:
         1791 
         1792      &lt;article&gt;
         1793              &lt;header&gt;
         1794                      &lt;h1&gt;&lt;a href=&quot;&quot;&gt;${title}&lt;/a&gt;&lt;/h1&gt;
         1795                      &lt;p&gt;
         1796                              &lt;strong&gt;Last modification on &lt;/strong&gt;
         1797                              &lt;time datetime=&quot;${updated}&quot;&gt;${updated}&lt;/time&gt;
         1798                      &lt;/p&gt;
         1799              &lt;/header&gt;
         1800              %{contentfile}
         1801      &lt;/article&gt;
         1802 
         1803 EXIT STATUS
         1804      The saait utility exits 0 on success, and &gt;0 if an error occurs.
         1805 
         1806 EXAMPLES
         1807      A basic usage example:
         1808 
         1809      1.          Create a directory for a new site:
         1810 
         1811           mkdir newsite
         1812 
         1813      2.          Copy the example pages, templates, global config file and example
         1814           stylesheets to a directory:
         1815 
         1816           cp -r pages templates config.cfg style.css print.css newsite/
         1817 
         1818      3.          Change the current directory to the created directory.
         1819 
         1820           cd newsite/
         1821 
         1822      4.          Change the values in the global config.cfg file.
         1823 
         1824      5.          If you want to modify parts of the header, like the navigation menu
         1825           items, you can change the following two template files:
         1826           templates/page/header.html
         1827           templates/index.html/header.html
         1828 
         1829      6.          Create any new pages in the pages directory.        For each config file
         1830           there has to be a corresponding HTML file.  By default this HTML
         1831           file has the path of the config file, but with the last extension
         1832           (&quot;.cfg&quot; in this case) replaced to &quot;.html&quot;.
         1833 
         1834      7.          Create an output directory:
         1835 
         1836           mkdir -p output
         1837 
         1838      8.          After any modifications the following commands can be used to
         1839           generate the output and process the pages in descending order:
         1840 
         1841           find pages -type f -name &#39;*.cfg&#39; -print0 | sort -zr | xargs -0 saait
         1842 
         1843      9.          Copy the modified stylesheets to the output directory also:
         1844 
         1845           cp style.css print.css output/
         1846 
         1847      10.  Open output/index.html locally in your webbrowser to review the
         1848           changes.
         1849 
         1850      11.  To synchronize files, you can securely transfer them via SSH using
         1851           rsync:
         1852 
         1853           rsync -av output/ user@somehost:/var/www/htdocs/
         1854 
         1855 TRIVIA
         1856      The most boring static page generator.
         1857 
         1858      Meaning of saai (dutch): boring, pronunciation of saait: site
         1859 
         1860 SEE ALSO
         1861      find(1), sort(1), xargs(1)
         1862 
         1863 AUTHORS
         1864      Hiltjo Posthuma &lt;hiltjo@codemadness.org&gt;</code></pre>
         1865 ]]></content>
         1866 </entry>
         1867 <entry>
         1868         <title type="text">Stagit: a static git page generator</title>
         1869         <link rel="alternate" type="text/html" href="https://www.codemadness.org/stagit.html" />
         1870         <id>https://www.codemadness.org/stagit.html</id>
         1871         <updated>2020-07-20T00:00:00Z</updated>
         1872         <published>2017-05-10T00:00:00Z</published>
         1873         <author>
         1874                 <name>hiltjo</name>
         1875                 <uri>https://www.codemadness.org</uri>
         1876         </author>
         1877         <summary type="text">a static git page generator</summary>
         1878         <content type="html"><![CDATA[<h1>Stagit: a static git page generator</h1>
         1879         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
         1880         <p>
         1881 stagit is a static page generator for git.
         1882 </p>
         1883 
         1884 <p>
         1885 <a href="/git/stagit/file/README.html">Read the README for more information about it</a>.
         1886 </p>
         1887 
         1888 <p>
         1889 My git repository uses stagit, you can see how it looks here:
         1890 <a href="/git/">https://codemadness.org/git/</a>.
         1891 </p>
         1892 
         1893 
         1894 <h2>Features</h2>
         1895 <ul>
         1896 <li>Log of all commits from HEAD.</li>
         1897 <li>Log and diffstat per commit.</li>
         1898 <li>Show file tree with linkable line numbers.</li>
         1899 <li>Show references: local branches and tags.</li>
         1900 <li>Detect README and LICENSE file from HEAD and link it as a webpage.</li>
         1901 <li>Detect submodules (.gitmodules file) from HEAD and link it as a webpage.</li>
         1902 <li>Atom feed log (atom.xml).</li>
         1903 <li>Make index page for multiple repositories with stagit-index.</li>
         1904 <li>After generating the pages (relatively slow) serving the files is very fast,
         1905     simple and requires little resources (because the content is static), only
         1906     a HTTP file server is required.</li>
         1907 <li>Security: all pages are static. No CGI or dynamic code is run for the
         1908     interface. Using it with a secure httpd such as OpenBSD httpd it is
         1909     privilege-separated, chroot(2)'d and pledge(2)'d.</li>
         1910 <li>Simple to setup: the content generation is clearly separated from serving
         1911     it. This makes configuration as simple as copying a few directories and
         1912     scripts.</li>
         1913 <li>Usable with text-browsers such as dillo, links, lynx and w3m.</li>
         1914 </ul>
         1915 
         1916 
         1917 <h2>Cons</h2>
         1918 <ul>
         1919 <li>Not suitable for large repositories (2000+ commits), because diffstats are
         1920     an expensive operation, the cache (-c flag) is a workaround for this in
         1921     some cases.</li>
         1922 <li>Not suitable for large repositories with many files, because all files are
         1923     written for each execution of stagit. This is because stagit shows the lines
         1924     of textfiles and there is no "cache" for file metadata (this would add more
         1925     complexity to the code).</li>
         1926 <li>Not suitable for repositories with many branches, a quite linear history is
         1927     assumed (from HEAD).</li>
         1928 </ul>
         1929 
         1930 <p>
         1931 In these cases it is better to use <a href="https://git.zx2c4.com/cgit/">cgit</a> or
         1932 possibly change stagit to run as a CGI program.
         1933 </p>
         1934 
         1935 <ul>
         1936 <li>Relatively slow to run the first time (about 3 seconds for sbase,
         1937     1500+ commits), incremental updates are faster.</li>
         1938 <li>Does not support some of the dynamic features cgit has, like:
         1939         <ul>
         1940         <li>Snapshot tarballs per commit.</li>
         1941         <li>File tree per commit.</li>
         1942         <li>History log of branches diverged from HEAD.</li>
         1943         <li>Stats (git shortlog -s).</li>
         1944         </ul>
         1945 </li>
         1946 </ul>
         1947 
         1948 <p>This is by design, just use git locally.</p>
         1949 
         1950 
         1951 <h2>Clone</h2>
         1952 <pre><code>git clone git://<a href="//git.codemadness.org/stagit/">git.codemadness.org/stagit</a></code></pre>
         1953 
         1954 
         1955 <h2>Download releases</h2>
         1956 <p>Releases are available at:
         1957 
         1958 <a href="https://codemadness.org/releases/stagit/">https://codemadness.org/releases/stagit/</a>
         1959 and a mirror at
         1960 <a href="https://dl.2f30.org/releases/">https://dl.2f30.org/releases/</a>stagit-*.tar.gz</p>
         1961 ]]></content>
         1962 </entry>
         1963 <entry>
         1964         <title type="text">OpenBSD httpd, slowcgi and cgit</title>
         1965         <link rel="alternate" type="text/html" href="https://www.codemadness.org/openbsd-httpd-and-cgit.html" />
         1966         <id>https://www.codemadness.org/openbsd-httpd-and-cgit.html</id>
         1967         <updated>2015-07-05T00:00:00Z</updated>
         1968         <published>2015-07-05T00:00:00Z</published>
         1969         <author>
         1970                 <name>hiltjo</name>
         1971                 <uri>https://www.codemadness.org</uri>
         1972         </author>
         1973         <summary type="text">OpenBSD httpd, slowcgi and cgit</summary>
         1974         <content type="html"><![CDATA[<h1>OpenBSD httpd, slowcgi and cgit</h1>
         1975         <p><strong>Last modification on </strong> <time>2015-07-05</time></p>
         1976         <p>
         1977 This is a guide to get <a href="https://git.zx2c4.com/cgit/">cgit</a> working with the
         1978 relatively new <a href="https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man8/httpd.8">OpenBSD httpd(8)</a> and
         1979 <a href="https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man8/slowcgi.8">slowcgi(8)</a> in base.
         1980 OpenBSD httpd is very simple to setup, but nevertheless this guide might help someone out there.
         1981 </p>
         1982 
         1983 
         1984 <h2>Installation</h2>
         1985 
         1986 <p>Install the cgit package:</p>
         1987 <pre><code># pkg_add cgit</code></pre>
         1988 
         1989 <p>or build it from ports:</p>
         1990 <pre><code># cd /usr/ports/www/cgit && make && make install</code></pre>
         1991 
         1992 
         1993 <h2>Configuration</h2>
         1994 
         1995 
         1996 <h3>httpd</h3>
         1997 <p>An example of <a href="https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/httpd.conf.5">httpd.conf(5)</a>:
         1998 <a href="downloads/openbsd-httpd/httpd.conf">httpd.conf</a>.</p>
         1999 
         2000 
         2001 <h3>slowcgi</h3>
         2002 <p>By default the slowcgi UNIX domain socket is located at: /var/www/run/slowcgi.sock.
         2003 For this example we use the defaults.</p>
         2004 
         2005 
         2006 <h3>cgit</h3>
         2007 <p>The cgit binary should be located at: /var/www/cgi-bin/cgit.cgi (default).</p>
         2008 
         2009 <p>cgit uses the $CGIT_CONFIG environment variable to locate it's config.
         2010 By default on OpenBSD this is set to /conf/cgitrc (chroot), which is /var/www/conf/cgitrc.
         2011 An example of cgitrc is here: <a href="downloads/openbsd-httpd/cgitrc">cgitrc</a>.</p>
         2012 
         2013 <p>In this example the cgit cache directory is set to /cgit/cache (chroot), which is /var/www/cgit/cache.
         2014 Make sure to give this path read and write permissions for cgit (www:daemon).</p>
         2015 
         2016 <p>In the example the repository path (scan-path) is set to /htdocs/src (chroot), which is /var/www/htdocs/src.</p>
         2017 
         2018 <p>The footer file is set to /conf/cgit.footer. Make sure this file exists or you will get warnings:</p>
         2019 <pre><code># >/var/www/conf/cgit.footer</code></pre>
         2020 
         2021 <p>Make sure cgit.css (stylesheet) and cgit.png (logo) are accessible, by default: /var/www/cgit/cgit.{css,png}
         2022 (location can be changed in httpd.conf).</p>
         2023 
         2024 <p>To support .tar.gz snapshots a static gzip binary is required in the chroot /bin directory:</p>
         2025 
         2026 <pre><code>cd /usr/src/usr.bin/compress
         2027 make clean && make LDFLAGS="-static -pie"
         2028 cp obj/compress /var/www/bin/gzip</code></pre>
         2029 
         2030 
         2031 <h2>Running the services</h2>
         2032 
         2033 <p>Enable the httpd and slowcgi services to automatically start them at boot:</p>
         2034 
         2035 <pre><code># rcctl enable httpd slowcgi</code></pre>
         2036 
         2037 <p>Start the services:</p>
         2038 
         2039 <pre><code># rcctl start httpd slowcgi</code></pre>
         2040 ]]></content>
         2041 </entry>
         2042 <entry>
         2043         <title type="text">twitch: application to watch Twitch streams</title>
         2044         <link rel="alternate" type="text/html" href="https://www.codemadness.org/twitch-interface.html" />
         2045         <id>https://www.codemadness.org/twitch-interface.html</id>
         2046         <updated>2020-05-06T00:00:00Z</updated>
         2047         <published>2014-11-23T00:00:00Z</published>
         2048         <author>
         2049                 <name>hiltjo</name>
         2050                 <uri>https://www.codemadness.org</uri>
         2051         </author>
         2052         <summary type="text">twitch: application to watch Twitch streams</summary>
         2053         <content type="html"><![CDATA[<h1>twitch: application to watch Twitch streams</h1>
         2054         <p><strong>Last modification on </strong> <time>2020-05-06</time></p>
         2055         <p>
         2056 <strong>Update: as of 2020-05-06:</strong> I stopped maintaining it.
         2057 Twitch now requires OAUTH and 2-factor authentication. It requires me to expose
         2058 personal information such as my phone number.
         2059 </p>
         2060 
         2061 <p>
         2062 <strong>Update: as of ~2020-01-03:</strong> I rewrote this application from Golang to C.
         2063 The Twitch Kraken API used by the Golang version was deprecated.
         2064 It is now rewritten to use the <a href="https://dev.twitch.tv/docs/api/reference">Helix API</a>.
         2065 It also has a <a href="gopher://codemadness.org/1/twitch.cgi">Gopher version</a> now.
         2066 You can still find the old code here:
         2067 <a href="https://git.codemadness.org/twitch-go/file/README.html">twitch-go</a>.
         2068 </p>
         2069 
         2070 <p>
         2071 This script allows to view streams in your own video player like
         2072 <a href="https://mpv.io/">mpv</a>, so the bloated Twitch interface is not needed.
         2073 It uses the Twitch Helix API and is written in C.
         2074 </p>
         2075 
         2076 
         2077 <h2 id="features">Features</h2>
         2078 <ul>
         2079 <li>No Javascript, cookies, CSS optional.</li>
         2080 <li>Works well in all browsers, including text-based ones.</li>
         2081 <li>Has a HTTP CGI and Gopher CGI version.</li>
         2082 <li>Atom feed for VODs.</li>
         2083 </ul>
         2084 
         2085 
         2086 <h2>Clone</h2>
         2087 <pre><code>git clone git://<a href="//git.codemadness.org/frontends/">git.codemadness.org/frontends</a></code></pre>
         2088 
         2089 
         2090 <h2>View</h2>
         2091 <ul>
         2092 <li><s><a href="https://twitch.codemadness.org/">You can view the HTTP CGI version here</a>.</s></li>
         2093 <li><s><a href="gopher://codemadness.org/1/twitch.cgi">You can view the Gopher CGI version here</a>.</s></li>
         2094 </ul>
         2095 ]]></content>
         2096 </entry>
         2097 <entry>
         2098         <title type="text">Userscript: focus input field</title>
         2099         <link rel="alternate" type="text/html" href="https://www.codemadness.org/userscript-focus-input-field.html" />
         2100         <id>https://www.codemadness.org/userscript-focus-input-field.html</id>
         2101         <updated>2014-03-02T00:00:00Z</updated>
         2102         <published>2014-03-02T00:00:00Z</published>
         2103         <author>
         2104                 <name>hiltjo</name>
         2105                 <uri>https://www.codemadness.org</uri>
         2106         </author>
         2107         <summary type="text">Userscript to focus the first input field on a page with a hotkey</summary>
         2108         <content type="html"><![CDATA[<h1>Userscript: focus input field</h1>
         2109         <p><strong>Last modification on </strong> <time>2014-03-02</time></p>
         2110         <p>
         2111 This is an userscript I wrote a while ago which allows to focus the first input field on a page with ctrl+space.
         2112 This is useful if a site doesn't specify the autofocus attribute for an input field and you don't want to switch to it using the mouse.
         2113 </p>
         2114 
         2115 
         2116 <h2>Download</h2>
         2117 <p><a href="downloads/input_focus.user.js">Download userscript input_focus.user.js</a></p>
         2118 ]]></content>
         2119 </entry>
         2120 <entry>
         2121         <title type="text">Userscript: Youtube circumvent age verification</title>
         2122         <link rel="alternate" type="text/html" href="https://www.codemadness.org/userscript-youtube-circumvent-age-verification.html" />
         2123         <id>https://www.codemadness.org/userscript-youtube-circumvent-age-verification.html</id>
         2124         <updated>2013-02-21T00:00:00Z</updated>
         2125         <published>2013-02-21T00:00:00Z</published>
         2126         <author>
         2127                 <name>hiltjo</name>
         2128                 <uri>https://www.codemadness.org</uri>
         2129         </author>
         2130         <summary type="text">Userscript to circumvent Youtube age verification and redirect to the video</summary>
         2131         <content type="html"><![CDATA[<h1>Userscript: Youtube circumvent age verification</h1>
         2132         <p><strong>Last modification on </strong> <time>2013-02-21</time></p>
         2133         <p>
         2134 This is an userscript I wrote a while ago which circumvents requiring to login with an account on Youtube if a video requires age verification.
         2135 </p>
         2136 
         2137 
         2138 <h2>Download</h2>
         2139 <p><a href="downloads/youtube_circumvent_sign_in.user.js">Download userscript Youtube_circumvent_sign_in.user.js</a></p>
         2140 ]]></content>
         2141 </entry>
         2142 <entry>
         2143         <title type="text">Userscript: block stupid fonts</title>
         2144         <link rel="alternate" type="text/html" href="https://www.codemadness.org/userscript-block-stupid-fonts.html" />
         2145         <id>https://www.codemadness.org/userscript-block-stupid-fonts.html</id>
         2146         <updated>2020-03-10T00:00:00Z</updated>
         2147         <published>2012-10-21T00:00:00Z</published>
         2148         <author>
         2149                 <name>hiltjo</name>
         2150                 <uri>https://www.codemadness.org</uri>
         2151         </author>
         2152         <summary type="text">Userscript to whitelist your favorite fonts and block the rest</summary>
         2153         <content type="html"><![CDATA[<h1>Userscript: block stupid fonts</h1>
         2154         <p><strong>Last modification on </strong> <time>2020-03-10</time></p>
         2155         <p>
         2156 This is an userscript I wrote a while ago which white-lists fonts I like and blocks the rest.
         2157 The reason I made this is because I don't like the inconsistency of custom fonts used on a lot of websites.
         2158 </p>
         2159 
         2160 
         2161 <h2>Download</h2>
         2162 
         2163 <p><a href="downloads/block_stupid_fonts_v1.2.user.js">Download userscript Block_stupid_fonts_v1.2.user.js</a></p>
         2164 
         2165 <p>Old version: <a href="downloads/block_stupid_fonts.user.js">Download userscript Block_stupid_fonts.user.js</a></p>
         2166 ]]></content>
         2167 </entry>
         2168 <entry>
         2169         <title type="text">Sfeed: simple RSS and Atom parser</title>
         2170         <link rel="alternate" type="text/html" href="https://www.codemadness.org/sfeed-simple-feed-parser.html" />
         2171         <id>https://www.codemadness.org/sfeed-simple-feed-parser.html</id>
         2172         <updated>2020-06-28T00:00:00Z</updated>
         2173         <published>2011-04-01T00:00:00Z</published>
         2174         <author>
         2175                 <name>hiltjo</name>
         2176                 <uri>https://www.codemadness.org</uri>
         2177         </author>
         2178         <summary type="text">Sfeed is a simple RSS and Atom parser (and format programs to add reader functionality)</summary>
         2179         <content type="html"><![CDATA[<h1>Sfeed: simple RSS and Atom parser</h1>
         2180         <p><strong>Last modification on </strong> <time>2020-06-28</time></p>
         2181         <p>Sfeed is a RSS and Atom parser (and some format programs).</p>
         2182 
         2183 <p>It converts RSS or Atom feeds from XML to a TAB-separated file. There are
         2184 formatting programs included to convert this TAB-separated format to various
         2185 other formats. There are also some programs and scripts included to import and
         2186 export OPML and to fetch, filter, merge and order feed items.</p>
         2187 
         2188 <p>For the most (up-to-date) information see the
         2189    <a href="/git/sfeed/file/README.html">README</a> file.</p>
         2190 
         2191 
         2192 <h2>Clone</h2>
         2193 <pre><code>git clone git://<a href="//git.codemadness.org/sfeed/">git.codemadness.org/sfeed</a></code></pre>
         2194 
         2195 
         2196 <h2>Download releases</h2>
         2197 <p>
         2198 Releases are available at:
         2199 <a href="/releases/sfeed/">https://codemadness.org/releases/sfeed/</a>.
         2200 </p>
         2201 
         2202 <p>NOTE: releases for sfeed can be seen as periodic snapshots. I recommend to
         2203 use the git version.</p>
         2204 
         2205 
         2206 <h2>Build and install</h2>
         2207 
         2208 <pre><code>$ make
         2209 # make install</code></pre>
         2210 
         2211 <h2>Screenshot and examples</h2>
         2212 <p><a href="downloads/screenshots/sfeed-screenshot.png"><img src="downloads/screenshots/sfeed-thumb.png" alt="Screenshot of sfeed piped to sfeed_plain using dmenu in vertical-list mode" width="400" height="232" loading="lazy" /></a></p>
         2213 
         2214 <p>The above screenshot uses the sfeed_plain format program with
         2215 <a href="https://tools.suckless.org/dmenu/">dmenu</a>.
         2216 This program outputs the feed items in a compact way per line as plain-text to
         2217 stdout.  The dmenu program reads these lines from stdin and displays them as a
         2218 X11 list menu. When an item is selected in dmenu it prints this item to stdout.
         2219 A simple written script can then filter for the url in this output and do some
         2220 action, like opening it in some browser or open a podcast in your music player.
         2221 </p>
         2222 
         2223 <p>For example:</p>
         2224 <pre><code>#!/bin/sh
         2225 url=$(sfeed_plain "$HOME/.sfeed/feeds/"* | dmenu -l 35 -i | \
         2226         sed -n 's@^.* \([a-zA-Z]*://\)\(.*\)$@\1\2@p')
         2227 test -n "${url}" && $BROWSER "${url}"</code></pre>
         2228 
         2229 <p>However this is just one way to format and interact with feed items.
         2230 See also the README for other practical examples.</p>
         2231 
         2232 <p>Below are some examples of output that are supported by the included format
         2233 programs:</p>
         2234 
         2235 <ul>
         2236         <li><a href="downloads/sfeed/plain/feeds.txt">plain text (UTF-8)</a></li>
         2237         <li><a href="downloads/sfeed/html/feeds.html">HTML (CSS)</a></li>
         2238         <li><a href="downloads/sfeed/frames/index.html">HTML frames</a></li>
         2239         <li>gopher</li>
         2240         <li><a href="downloads/sfeed/mbox/feeds.mbox">mbox</a></li>
         2241         <li><a href="downloads/sfeed/twtxt/twtxt.txt">twtxt</a></li>
         2242         <li><a href="downloads/sfeed/atom/feeds.xml">atom</a></li>
         2243 </ul>
         2244 
         2245 <p>
         2246 For a separate curses UI front-end, see also <a href="sfeed_curses-ui.html">sfeed_curses</a>.
         2247 </p>
         2248 ]]></content>
         2249 </entry>
         2250 <entry>
         2251         <title type="text">Vim theme: relaxed</title>
         2252         <link rel="alternate" type="text/html" href="https://www.codemadness.org/vim-theme-relaxed.html" />
         2253         <id>https://www.codemadness.org/vim-theme-relaxed.html</id>
         2254         <updated>2011-01-07T00:00:00Z</updated>
         2255         <published>2011-01-07T00:00:00Z</published>
         2256         <author>
         2257                 <name>hiltjo</name>
         2258                 <uri>https://www.codemadness.org</uri>
         2259         </author>
         2260         <summary type="text">a dark VIM theme I made and use on a daily basis</summary>
         2261         <content type="html"><![CDATA[<h1>Vim theme: relaxed</h1>
         2262         <p><strong>Last modification on </strong> <time>2011-01-07</time></p>
         2263         <p>This is a dark theme I made for <a href="http://www.vim.org/">vim</a>.
         2264 This is a theme I personally used for quite a while now and over time tweaked to my liking.
         2265 It is made for gvim, but also works for 16-colour terminals (with small visual differences).
         2266 The relaxed.vim file also has my .Xdefaults file colours listed at the top for 16+-colour
         2267 terminals on X11.</p>
         2268 
         2269 <p>It is inspired by the "desert" theme available at <a href="https://www.vim.org/scripts/script.php?script_id=105">https://www.vim.org/scripts/script.php?script_id=105</a>,
         2270 although I removed the cursive and bold styles and changed some colours I didn't like.</p>
         2271 
         2272 
         2273 <h2>Download</h2>
         2274 
         2275 <p><a href="downloads/themes/vim/relaxed.vim">relaxed.vim</a></p>
         2276 
         2277 
         2278 <h2>Screenshot</h2>
         2279 
         2280 <p><a href="downloads/themes/vim/vim_relaxed_theme.png"><img src="downloads/themes/vim/vim_relaxed_theme_thumb.png" alt="Screenshot of VIM theme relaxed on the left is gvim (GUI), on the right is vim in urxvt (terminal)" width="480" height="300" loading="lazy" /></a></p>
         2281 ]]></content>
         2282 </entry>
         2283 <entry>
         2284         <title type="text">Seturgent: set urgency hints for X applications</title>
         2285         <link rel="alternate" type="text/html" href="https://www.codemadness.org/seturgent-set-urgency-hints-for-x-applications.html" />
         2286         <id>https://www.codemadness.org/seturgent-set-urgency-hints-for-x-applications.html</id>
         2287         <updated>2020-07-20T00:00:00Z</updated>
         2288         <published>2010-10-31T00:00:00Z</published>
         2289         <author>
         2290                 <name>hiltjo</name>
         2291                 <uri>https://www.codemadness.org</uri>
         2292         </author>
         2293         <summary type="text">Seturgent is a small utility to set an application it&#39;s urgency hint</summary>
         2294         <content type="html"><![CDATA[<h1>Seturgent: set urgency hints for X applications</h1>
         2295         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
         2296         <p>
         2297 Seturgent is a small utility to set an application it's urgency hint.
         2298 For most windowmanager's and panel applications this will highlight
         2299 the application and will allow special actions.
         2300 </p>
         2301 
         2302 
         2303 <h2>Clone</h2>
         2304 <pre><code>git clone git://<a href="//git.codemadness.org/seturgent/">git.codemadness.org/seturgent</a></code></pre>
         2305 
         2306 
         2307 <h2>Download releases</h2>
         2308 <p>
         2309 Releases are available at:
         2310 <a href="/releases/seturgent/">https://codemadness.org/releases/seturgent/</a>.
         2311 </p>
         2312 ]]></content>
         2313 </entry>
         2314 <entry>
         2315         <title type="text">GTK2 theme: gtk-murrine-rape</title>
         2316         <link rel="alternate" type="text/html" href="https://www.codemadness.org/gtk2-theme-gtk-murrine-rape.html" />
         2317         <id>https://www.codemadness.org/gtk2-theme-gtk-murrine-rape.html</id>
         2318         <updated>2010-10-31T00:00:00Z</updated>
         2319         <published>2010-10-31T00:00:00Z</published>
         2320         <author>
         2321                 <name>hiltjo</name>
         2322                 <uri>https://www.codemadness.org</uri>
         2323         </author>
         2324         <summary type="text">A plain consistent GTK2 theme with no fluff (rounded borders, animations, etc)</summary>
         2325         <content type="html"><![CDATA[<h1>GTK2 theme: gtk-murrine-rape</h1>
         2326         <p><strong>Last modification on </strong> <time>2010-10-31</time></p>
         2327         <h2>Download</h2>
         2328 <p><a href="downloads/themes/gtk/murrine-rape/gtk-2.0/gtkrc">gtkrc</a></p>
         2329 
         2330 
         2331 <h2>Screenshot</h2>
         2332 <p><a href="downloads/themes/gtk/murrine-rape/gtk-murrine-rape.png"><img src="downloads/themes/gtk/murrine-rape/gtk-murrine-rape-thumb.png" alt="Screenshot of gtk engine murrine: murrine-rape theme" width="480" height="300" loading="lazy" /></a></p>
         2333 
         2334 
         2335 <h2>Features</h2>
         2336 <ul>
         2337 <li>Good contrast between UI elements and consistency (imho).</li>
         2338 <li>Plain colours; no bright colours and (almost) no gradients.</li>
         2339 <li>No rounded borders.</li>
         2340 <li>No animations (progressbar etc).</li>
         2341 <li>Uses the fast and easy customizable gtk-engine-murrine.</li>
         2342 </ul>
         2343 
         2344 
         2345 <h2>Dependency</h2>
         2346 <p>Depends on the git version of gtk-engine-murrine last I checked:
         2347 <a href="http://www.cimitan.com/murrine/">http://www.cimitan.com/murrine/</a>
         2348 (link broken 2017-08-04).</p>
         2349 ]]></content>
         2350 </entry>
         2351 <entry>
         2352         <title type="text">DWM-hiltjo: my windowmanager configuration</title>
         2353         <link rel="alternate" type="text/html" href="https://www.codemadness.org/dwm-hiltjo-my-windowmanager-configuration.html" />
         2354         <id>https://www.codemadness.org/dwm-hiltjo-my-windowmanager-configuration.html</id>
         2355         <updated>2020-07-20T00:00:00Z</updated>
         2356         <published>2010-08-12T00:00:00Z</published>
         2357         <author>
         2358                 <name>hiltjo</name>
         2359                 <uri>https://www.codemadness.org</uri>
         2360         </author>
         2361         <summary type="text">My DWM configuration; a few added features to suit my needs</summary>
         2362         <content type="html"><![CDATA[<h1>DWM-hiltjo: my windowmanager configuration</h1>
         2363         <p><strong>Last modification on </strong> <time>2020-07-20</time></p>
         2364         <p>As you might know DWM is a very minimal windowmanager: <a href="https://dwm.suckless.org/">https://dwm.suckless.org/</a>.
         2365 It's known to only have the most essential features one needs, everything else is "do-it-yourself" or extending it with the
         2366 many available <a href="https://dwm.suckless.org/patches/">patches</a>. The vanilla version is less than 2000 SLOC, because
         2367 of this it's quite easy in my opinion to see how it works and modify it.</p>
         2368 
         2369 <p>I really like my configuration at the moment and want to share my changes. Some of the features listed below are patches from suckless.org I applied, but there are also some changes I made.</p>
         2370 
         2371 <p><em>Disclaimer: this configuration is entirely made for my personal preferences so you might not like it at all :)</em></p>
         2372 
         2373 
         2374 <h2>Features</h2>
         2375 <ul>
         2376         <li>Titlebar:
         2377                 <ul>
         2378                         <li>Shows all clients of the selected / active tags.</li>
         2379                         <li>Divide application bars evenly among available space (awesomewm-like taskbar).</li>
         2380                         <li>Colour urgent clients in the taskbar on active tags.</li>
         2381                         <li>Left-click focuses clicked client.</li>
         2382                         <li>Right-click toggles monocle layout.</li>
         2383                         <li>Middle-click kills the clicked client.</li>
         2384                 </ul>
         2385         </li>
         2386         <li>Tagbar:
         2387                 <ul>
         2388                         <li>Only show active tags.</li>
         2389                         <li>Colour inactive tags with urgent clients.</li>
         2390                 </ul>
         2391         </li>
         2392         <li>Layouts:
         2393                 <ul>
         2394                         <li>Cycle layouts with Modkey + Space (next) and Modkey + Control + Space (previous).</li>
         2395                         <li>Fullscreen layout (hides topbar and removes borders).</li>
         2396                 </ul>
         2397         </li>
         2398         <li>Other:
         2399                 <ul>
         2400                         <li>Move tiled clients around with the mouse (drag-move), awesomewm-like.</li>
         2401                         <li>Add some keybinds for multimedia keyboards (audio play / pause, mute, www, volume buttons, etc).</li>
         2402                 </ul>
         2403         </li>
         2404         <li>... and more ;) ...</li>
         2405 </ul>
         2406 
         2407 <p>
         2408 NOTES: I removed application icons (_NET_WM_ICON support), but if you want it for some reason you can find it in the history of this repo.
         2409 Pertag-like behaviour is also removed since it's wrong.
         2410 Cycling through urgent clients is also removed.
         2411 </p>
         2412 
         2413 
         2414 <h2>Clone</h2>
         2415 <pre><code>git clone -b hiltjo git://<a href="//git.codemadness.org/dwm/">git.codemadness.org/dwm</a></code></pre>
         2416 
         2417 
         2418 <h2>Screenshot</h2>
         2419 <p><a href="downloads/screenshots/dwm-screenshot.png"><img src="downloads/screenshots/dwm-screenshot-thumb.png" alt="Screenshot showing what dwm-hiltjo looks like" width="480" height="300" loading="lazy" /></a></p>
         2420 ]]></content>
         2421 </entry>
         2422 <entry>
         2423         <title type="text">Query unused CSS rules on current document state</title>
         2424         <link rel="alternate" type="text/html" href="https://www.codemadness.org/query-unused-css-rules-on-current-document-state.html" />
         2425         <id>https://www.codemadness.org/query-unused-css-rules-on-current-document-state.html</id>
         2426         <updated>2010-04-21T00:00:00Z</updated>
         2427         <published>2010-04-21T00:00:00Z</published>
         2428         <author>
         2429                 <name>hiltjo</name>
         2430                 <uri>https://www.codemadness.org</uri>
         2431         </author>
         2432         <summary type="text">How to see all the rules in a stylesheet (CSS) that are not used for the current document</summary>
         2433         <content type="html"><![CDATA[<h1>Query unused CSS rules on current document state</h1>
         2434         <p><strong>Last modification on </strong> <time>2010-04-21</time></p>
         2435         <p>
         2436 Today I was doing some web development and wanted to see all the rules
         2437 in a stylesheet (CSS) that were not used for the current document. I
         2438 wrote the following Javascript code which you can paste in the Firebug
         2439 console and run:
         2440 </p>
         2441 
         2442 <pre><code>(function() {
         2443         for (var i=0;i&lt;document.styleSheets.length;i++) {
         2444                 var rules = document.styleSheets[i].cssRules || [];
         2445                 var sheethref = document.styleSheets[i].href || 'inline';
         2446                 for (var r=0;r&lt;rules.length;r++)
         2447                         if (!document.querySelectorAll(rules[r].selectorText).length)
         2448                                 console.log(sheethref + ': "' + rules[r].selectorText + '" not found.');
         2449         }
         2450 })();
         2451 </code></pre>
         2452 
         2453 <p>This will output all the (currently) unused CSS rules per selector, the output can be for example:</p>
         2454 
         2455 <pre><code>http://www.codemadness.nl/blog/wp-content/themes/codemadness/style.css: "fieldset, a img" not found.
         2456 http://www.codemadness.nl/blog/wp-content/themes/codemadness/style.css: "#headerimg" not found.
         2457 http://www.codemadness.nl/blog/wp-content/themes/codemadness/style.css: "a:hover" not found.
         2458 http://www.codemadness.nl/blog/wp-content/themes/codemadness/style.css: "h2 a:hover, h3 a:hover" not found.
         2459 http://www.codemadness.nl/blog/wp-content/themes/codemadness/style.css: ".postmetadata-center" not found.
         2460 http://www.codemadness.nl/blog/wp-content/themes/codemadness/style.css: ".thread-alt" not found.
         2461 </code></pre>
         2462 
         2463 <p>Just a trick I wanted to share, I hope someone finds this useful :)</p>
         2464 
         2465 <p>For webkit-based browsers you can use "Developer Tools" and use "Audits" under "Web Page Performance" it says "Remove unused CSS rules". For Firefox there is also Google Page Speed: <a href="https://code.google.com/speed/page-speed/">https://code.google.com/speed/page-speed/</a> this adds an extra section under Firebug.</p>
         2466 
         2467 <p>Tested on Chrome and Firefox.</p>
         2468 ]]></content>
         2469 </entry>
         2470 <entry>
         2471         <title type="text">Driconf: enabling S3 texture compression on Linux</title>
         2472         <link rel="alternate" type="text/html" href="https://www.codemadness.org/driconf-enabling-s3-texture-compression-on-linux.html" />
         2473         <id>https://www.codemadness.org/driconf-enabling-s3-texture-compression-on-linux.html</id>
         2474         <updated>2020-08-21T00:00:00Z</updated>
         2475         <published>2009-07-05T00:00:00Z</published>
         2476         <author>
         2477                 <name>hiltjo</name>
         2478                 <uri>https://www.codemadness.org</uri>
         2479         </author>
         2480         <summary type="text">driconf: enabling S3 texture compression</summary>
         2481         <content type="html"><![CDATA[<h1>Driconf: enabling S3 texture compression on Linux</h1>
         2482         <p><strong>Last modification on </strong> <time>2020-08-21</time></p>
         2483         <p><strong>Update: the DXTC patent expired on 2018-03-16, many distros enable this by default now.</strong></p>
         2484 
         2485 <p>
         2486 S3TC (also known as DXTn or DXTC) is a patented lossy texture compression algorithm.
         2487 See: <a href="https://en.wikipedia.org/wiki/S3TC">https://en.wikipedia.org/wiki/S3TC</a> for more detailed information.
         2488 Many games use S3TC and if you use Wine to play games you definitely want to enable it if your graphics card supports it.
         2489 
         2490 Because this algorithm was <a href="https://dri.freedesktop.org/wiki/S3TC/">patented it is disabled by default on many Linux distributions</a>.
         2491 </p>
         2492 
         2493 <p>
         2494 To enable it you can install the library "libtxc" if your favorite OS has not installed it already.
         2495 
         2496 For easy configuration you can install the optional utility DRIconf, which you can find at: <a href="http://dri.freedesktop.org/wiki/DriConf">http://dri.freedesktop.org/wiki/DriConf</a>.
         2497 DriConf can safely be removed after configuration.
         2498 </p>
         2499 
         2500 
         2501 <h2>Steps to enable it</h2>
         2502 <ol>
         2503 <li>
         2504         <p>Install libtxc_dxtn</p>
         2505         <p>ArchLinux:</p>
         2506         <pre><code># pacman -S libtxc_dxtn</code></pre>
         2507         <p>Debian:</p>
         2508         <pre><code># aptitude install libtxc-dxtn-s2tc0</code></pre>
         2509 </li>
         2510 <li>
         2511         <p>Install driconf (optional).</p>
         2512         <p>ArchLinux:</p>
         2513         <pre><code># pacman -S driconf</code></pre>
         2514         <p>Debian:</p>
         2515         <pre><code># aptitude install driconf</code></pre>
         2516 </li>
         2517 <li>
         2518         <p>Run driconf and enable S3TC</p>
         2519         <a href="downloads/screenshots/driconf.png"><img src="downloads/screenshots/driconf-thumb.png" alt="Screenshot of DRIconf window and it's options" width="300" height="266" loading="lazy" /></a>
         2520 </li>
         2521 </ol>
         2522 
         2523 
         2524 <h2>Additional links</h2>
         2525 <ol>
         2526         <li>S3TC: <a href="https://dri.freedesktop.org/wiki/S3TC/">https://dri.freedesktop.org/wiki/S3TC/</a></li>
         2527         <li>DriConf: <a href="https://dri.freedesktop.org/wiki/DriConf">https://dri.freedesktop.org/wiki/DriConf</a></li>
         2528 </ol>
         2529 ]]></content>
         2530 </entry>
         2531 <entry>
         2532         <title type="text">Getting the USB-powerline bridge to work on Linux</title>
         2533         <link rel="alternate" type="text/html" href="https://www.codemadness.org/getting-the-usb-powerline-bridge-to-work-on-linux.html" />
         2534         <id>https://www.codemadness.org/getting-the-usb-powerline-bridge-to-work-on-linux.html</id>
         2535         <updated>2019-12-06T00:00:00Z</updated>
         2536         <published>2009-04-13T00:00:00Z</published>
         2537         <author>
         2538                 <name>hiltjo</name>
         2539                 <uri>https://www.codemadness.org</uri>
         2540         </author>
         2541         <summary type="text">A guide to get a USB-powerline bridge with the Intellon 51x1 chipset working on Linux</summary>
         2542         <content type="html"><![CDATA[<h1>Getting the USB-powerline bridge to work on Linux</h1>
         2543         <p><strong>Last modification on </strong> <time>2019-12-06</time></p>
         2544         <p><strong>NOTE: this guide is obsolete, a working driver is now included in the Linux kernel tree (<a href="https://lkml.org/lkml/2009/4/18/121">since Linux 2.6.31</a>)</strong></p>
         2545 
         2546 <h2>Introduction</h2>
         2547 <p>
         2548 A USB to powerline bridge is a network device that instead of using an ordinary Ethernet cable (CAT5 for example) or wireless LAN it uses the powerlines as a network to communicate with similar devices.
         2549 A more comprehensive explanation of what it is and how it works you can find <a href="https://en.wikipedia.org/wiki/IEEE_1901">here</a>.
         2550 </p>
         2551 
         2552 <p>Known products that use the Intellon 51x1 chipset:</p>
         2553 <ul>
         2554         <li>MicroLink dLAN USB</li>
         2555         <li>"Digitus network"</li>
         2556         <li>Intellon USB Ethernet powerline adapter</li>
         2557         <li>Lots of other USB-powerline adapters...</li>
         2558 </ul>
         2559 
         2560 <p>To check if your device is supported:</p>
         2561 <pre><code>$ lsusb | grep -i 09e1
         2562 Bus 001 Device 003: ID 09e1:5121 Intellon Corp.</code></pre>
         2563 <p>If the vendor (09e1) and product (5121) ID match then it's probably supported.</p>
         2564 
         2565 
         2566 <h2>Installation</h2>
         2567 <p>Get drivers from the official site<sup><a href="http://www.devolo.co.uk/consumer/downloads-44-microlink-dlan-usb.html?l=en">1</a></sup> or here<sup><a href="downloads/int51x1/dLAN-linux-package-v4.tar.gz">2</a></sup>. The drivers from the official site are more up-to-date.</p>
         2568 
         2569 <p>Extract them:</p>
         2570 <pre><code>$ tar -xzvf dLAN-linux-package-v4.tar.gz</code></pre>
         2571 
         2572 <p>Go to the extracted directory and compile them:</p>
         2573 <pre><code>$ ./configure
         2574 $ make</code></pre>
         2575 
         2576 <p>Depending on the errors you got you might need to download<sup><a href="downloads/int51x1/int51x1.patch">3</a></sup> and apply my patch:</p>
         2577 <pre><code>$ cd dLAN-linux-package-v4/     (or other path to the source code)
         2578 $ patch &lt; int51x1.patch</code></pre>
         2579 
         2580 <p>Try again:</p>
         2581 <pre><code>$ ./configure
         2582 $ make</code></pre>
         2583 
         2584 <p>If that failed try:</p>
         2585 <pre><code>$ ./configure
         2586 $ KBUILD_NOPEDANTIC=1 make</code></pre>
         2587 
         2588 <p>If that went OK install the drivers (as root):</p>
         2589 <pre><code># make install</code></pre>
         2590 
         2591 <p>Check if the "devolo_usb" module is loaded:</p>
         2592 <pre><code>$ lsmod | grep -i devolo_usb</code></pre>
         2593 <p>If it shows up then it's loaded. Now check if the interface is added:</p>
         2594 <pre><code>$ ifconfig -a | grep -i dlanusb
         2595 dlanusb0 Link encap:Ethernet HWaddr 00:12:34:56:78:9A</code></pre>
         2596 
         2597 
         2598 <h2>Configuration</h2>
         2599 <p>It is assumed you use a static IP, otherwise you can just use your DHCP client to get an unused IP address from your DHCP server. Setting up the interface is done like this (change the IP address and netmask accordingly if it's different):</p>
         2600 <pre><code># ifconfig dlanusb0 192.168.2.12 netmask 255.255.255.0</code></pre>
         2601 
         2602 
         2603 <h2>Checking if the network works</h2>
         2604 <p>Try to ping an IP address on your network to test for a working connection:</p>
         2605 <pre><code>$ ping 192.168.2.1
         2606 PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
         2607 64 bytes from 192.168.2.1: icmp_seq=1 ttl=30 time=2.49 ms
         2608 64 bytes from 192.168.2.1: icmp_seq=2 ttl=30 time=3.37 ms
         2609 64 bytes from 192.168.2.1: icmp_seq=3 ttl=30 time=2.80 ms
         2610 --- 192.168.2.1 ping statistics ---
         2611 3 packets transmitted, 3 received, 0% packet loss, time 2005ms
         2612 rtt min/avg/max/mdev = 2.497/2.891/3.374/0.368 ms</code></pre>
         2613 
         2614 <p>
         2615 You can now set up a network connection like you normally do with any Ethernet device.
         2616 The route can be added like this for example:</p>
         2617 <pre><code># route add -net 0.0.0.0 netmask 0.0.0.0 gw 192.168.2.1 dlanusb0</code></pre>
         2618 
         2619 <p>Change the IP address of your local gateway accordingly. Also make sure your nameserver is set in /etc/resolv.conf, something like:</p>
         2620 <pre><code>nameserver 192.168.2.1</code></pre>
         2621 
         2622 <p>Test your internet connection by doing for example:</p>
         2623 <pre><code>$ ping codemadness.org
         2624 PING codemadness.org (64.13.232.151) 56(84) bytes of data.
         2625 64 bytes from acmkoieeei.gs02.gridserver.com (64.13.232.151): icmp_seq=1 ttl=52 time=156 ms
         2626 64 bytes from acmkoieeei.gs02.gridserver.com (64.13.232.151): icmp_seq=2 ttl=52 time=156 ms
         2627 64 bytes from acmkoieeei.gs02.gridserver.com (64.13.232.151): icmp_seq=3 ttl=52 time=155 ms
         2628 --- codemadness.org ping statistics ---
         2629 3 packets transmitted, 3 received, 0% packet loss, time 1999ms
         2630 rtt min/avg/max/mdev = 155.986/156.312/156.731/0.552 ms</code></pre>
         2631 
         2632 <p>
         2633 If this command failed you probably have not setup your DNS/gateway properly.
         2634 If it worked then good for you :)
         2635 </p>
         2636 
         2637 
         2638 <h2>References</h2>
         2639 <ol>
         2640         <li><a href="http://www.devolo.co.uk/consumer/downloads-44-microlink-dlan-usb.html?l=en">Devolo download page with drivers (USB version).</a></li>
         2641         <li><a href="downloads/int51x1/dLAN-linux-package-v4.tar.gz">dLAN-linux-package-v4.tar.gz</a></li>
         2642         <li><a href="downloads/int51x1/int51x1.patch">Patch for recent 2.6.x kernels</a></li>
         2643         <li><a href="downloads/int51x1/INT51X1_datasheet.pdf">INT51X1 datasheet</a></li>
         2644 </ol>
         2645 ]]></content>
         2646 </entry>
         2647 <entry>
         2648         <title type="text">Gothic 1 game guide</title>
         2649         <link rel="alternate" type="text/html" href="https://www.codemadness.org/gothic-1-guide.html" />
         2650         <id>https://www.codemadness.org/gothic-1-guide.html</id>
         2651         <updated>2020-04-30T00:00:00Z</updated>
         2652         <published>2009-04-12T00:00:00Z</published>
         2653         <author>
         2654                 <name>hiltjo</name>
         2655                 <uri>https://www.codemadness.org</uri>
         2656         </author>
         2657         <summary type="text">Gothic 1 game guide with some useful tips</summary>
         2658         <content type="html"><![CDATA[<h1>Gothic 1 game guide</h1>
         2659         <p><strong>Last modification on </strong> <time>2020-04-30</time></p>
         2660         <p>Disclaimer: <em>
         2661 Some (including myself) may find some of these hints/exploits cheating. This
         2662 guide is just for educational and fun purposes. Some of these hints/tips apply
         2663 to Gothic 2 as well. I got the meat exploit from a guide somewhere on the
         2664 internet I can't recall where, anyway kudos to that person. The other exploits
         2665 I discovered myself. If you use some hints or exploits from these guide,
         2666 please add me to your "credits", I will appreciate it :)
         2667 </em></p>
         2668 
         2669 
         2670 <h2>Configuration</h2>
         2671 
         2672 
         2673 <h3>Widescreen resolution</h3>
         2674 <p>
         2675 Gothic supports widescreen resolutions with a small tweak, add the following
         2676 text string as a command-line argument:
         2677 </p>
         2678 
         2679 <pre><code>-zRes:1920,1200,32</code></pre>
         2680 
         2681 <p>
         2682 This also works for Gothic 2. Here 1920 is the width, 1200 the height and
         2683 32 the bits per pixel, change this to your preferred resolution.
         2684 </p>
         2685 
         2686 
         2687 <h3>Fix crash with Steam version</h3>
         2688 <p>
         2689 Disable steam overlay. If that doesn't work rename GameOverlayRenderer.dll in
         2690 your steam folder to _GameOverlayRenderer.dll.
         2691 </p>
         2692 
         2693 <p>I strongly recommend to buy the better version from <a
         2694 href="https://www.gog.com/game/gothic">GOG.com</a>.  The GOG version has no DRM
         2695 and allows easier modding, it also allows playing in most published languages:
         2696 German, English, Polish, furthermore it has some original artwork and
         2697 soundtrack included.</p>
         2698 
         2699 <h3>Upgrade Steam version to stand-alone version and remove Steam DRM (Gothic 1 and 2)</h3>
         2700 <p>You can install the Gothic playerkit and patches to remove the Steam DRM.</p>
         2701 
         2702 <p><a href="https://www.worldofgothic.de/">WorldOfGothic</a> playerkit patches:</p>
         2703 
         2704 <ul>
         2705 <li>Gothic 1 (EN): <a href="http://www.worldofgothic.com/dl/?go=dlfile&fileid=28">http://www.worldofgothic.com/dl/?go=dlfile&fileid=28</a></li>
         2706 <li>Gothic 1 (DE): <a href="https://www.worldofgothic.de/dl/download_34.htm">https://www.worldofgothic.de/dl/download_34.htm</a></li>
         2707 <li>Gothic 2 (EN/DE): <a href="https://www.worldofgothic.de/dl/download_168.htm">https://www.worldofgothic.de/dl/download_168.htm</a></li>
         2708 </ul>
         2709 
         2710 
         2711 <h3>Play Gothic in a different language with English subtitles (works best with GOG version)</h3>
         2712 
         2713 <p>If you're like me and have played the English version many times, but would
         2714 like to hear the (original) voice audio or if you would like to play with
         2715 different audio than you're used to, then you can copy the speech.vdf file of
         2716 your preferred version to your game files. Optionally turn on subtitles. I've
         2717 used this to play the English version of Gothic with the original German voice
         2718 audio and English subtitles.</p>
         2719 
         2720 
         2721 <h2>Easy money/weapons/armour/other items</h2>
         2722 
         2723 
         2724 <h3>Steal from Huno</h3>
         2725 <p>At night attack Huno the smith in the Old Camp and steal all his steel. Then
         2726 make some weapons and sell them with a merchant.  When you ask Huno about
         2727 blacksmith equipment it will respawn with 5 of each kind of steel. This is also
         2728 a fairly good starting weapon (requires 20 strength).  Also his chest located
         2729 near the sharpening stone and fire contains some steel as well, lock-pick it.
         2730 The combination is: RRLRLL. The chest contains _at least_ 20 raw steel, forge
         2731 it to get 20 crude swords which you can sell for 50 ore each to a merchant.
         2732 This will generate some nice starting money (1000+ ore) :)</p>
         2733 
         2734 
         2735 <h3>Steal weapons from the castle in the Old camp</h3>
         2736 <p>This tip is useful for getting pretty good starting weapons.</p>
         2737 
         2738 <p>Before entering the castle itself drop your ore (Left control + down for me)
         2739 in front of it. This will ensure when you get caught (and you probably will ;))
         2740 no ore will get stolen by the guards. Now use the "slip past guard" technique
         2741 described below and you should be able to get into Gomez his castle. Run to the
         2742 left where some weapons are stored. Now make sure you at least steal the best
         2743 weapon (battle sword) and steal as much as you can until you get whacked.  I
         2744 usually stand in the corner since that's where the best weapons are (battle
         2745 sword, judgement sword, etc). You'll now have some nice starting weapon(s) and
         2746 the good thing is they require very little attributes (about 13 strength).</p>
         2747 
         2748 
         2749 <h3>Free scraper armour the new camp</h3>
         2750 <p>In the new camp go to the mine and talk to Swiney at the bottom of "The
         2751 Hollow". Ask who he is and then ask to join the scrapers.  He will give you a
         2752 "Diggers dress" worth 250 ore. It has the following stats: + 10 against
         2753 weapons. + 5 against fire.  This will also give you free entrance to the bar in
         2754 the new camp.</p>
         2755 
         2756 <h3>Unlimited water bottles in the new camp</h3>
         2757 <p>In the quest from Lefty you will be assigned to get water bottles from the
         2758 rice lord.  He will give you infinite amounts of water bottles, in batches of
         2759 12.</p>
         2760 
         2761 
         2762 <h3>Armour amulet and increase HP potion</h3>
         2763 <p>
         2764 In the old camp in the main castle there are at least 3 chests with valuable items that don't require a key:
         2765 </p>
         2766 <ul>
         2767         <li>Middle right side (looking from the entrance), 1 chest:
         2768                 <ul>
         2769                         <li>lock combination: LLLLRLRL</li>
         2770                         <li>loot:
         2771                                 <ul>
         2772                                         <li>+15 against weapons, +15 against arrows (amulet of stone skin) (worth: 1000 ore)</li>
         2773                                 </ul>
         2774                         </li>
         2775                         <li>additionally there are 2 locked doors at the right side in this room. In
         2776                             the final room there are 3 floors with lots of chests.</li>
         2777                 </ul>
         2778         </li>
         2779         <li>Left side, 1 chest:
         2780                 <ul>
         2781                         <li>lock combination: RLLLLLRR</li>
         2782                         <li>loot:
         2783                                 <ul>
         2784                                         <li>+8 mana amulet (worth: 600 ore)</li>
         2785                                         <li>2 potions (+70 hp)</li>
         2786                                         <li>dreamcall (weed)</li>
         2787                                         <li>120 coins (worth: nothing)</li>
         2788                                 </ul>
         2789                         </li>
         2790                 </ul>
         2791         </li>
         2792         <li>Right side, 2 chests with:
         2793                 <ul>
         2794                         <li>lock combination: RLLLRLLR</li>
         2795                         <li>loot:
         2796                                 <ul>
         2797                                         <li>armour amulets, +15 against weapons (worth: 600 ore)</li>
         2798                                         <li>maximum life potion, +10 maximum life (worth: 1000 ore)</li>
         2799                                         <li>speed potion (1 minute duration)</li>
         2800                                         <li>4 potions (+70 hp)</li>
         2801                                 </ul>
         2802                         </li>
         2803                 </ul>
         2804         </li>
         2805 </ul>
         2806 
         2807 
         2808 <h3>Swamp camp harvest twice</h3>
         2809 
         2810 <p>In the swamp-weed harvest quest you must get swamp-weed for a guru. After
         2811 this quest you can get the harvest again, but you can keep the harvest without
         2812 consequences.</p>
         2813 
         2814 <h2>Exploits</h2>
         2815 
         2816 
         2817 <h3>Slip past guards</h3>
         2818 
         2819 <p>This exploit is really simple, just draw your weapon before you're
         2820 "targeted" by the guard and run past them this bypasses the dialog sequence.
         2821 When you're just out of their range holster your weapon again, so the people
         2822 around won't get pissed off.</p>
         2823 
         2824 <p>Works really well on the guards in front of the Old camp's castle, Y'Berrion
         2825 templars and New camp mercenaries near the Water magicians, just to name a
         2826 few.</p>
         2827 
         2828 <h3>Meat duplication</h3>
         2829 <p>Go to a pan and focus / target it so it says "frying pan" or similar. Now
         2830 open your inventory and select the meat. Now cook the meat (for me Left Control
         2831 + Arrow up). The inventory should remain open. You'll now have twice as much
         2832 meat as you had before. Do this a few times and you'll have a lot of meat, easy
         2833 for trading with ore/other items as well.</p>
         2834 
         2835 
         2836 <h3>Fall from great heights</h3>
         2837 <p>When you fall or jump from where you usually get fall damage you can do the
         2838 following trick: slightly before the ground use left or right strafe.
         2839 This works because it resets the falling animation. There are also other ways
         2840 to achieve the same thing such as attacking with a weapon in the air.
         2841 </p>
         2842 
         2843 
         2844 <h2>Experience / level up tips</h2>
         2845 
         2846 
         2847 <h3>Test of faith (extra exp)</h3>
         2848 <p>You get an additional 750 exp (from Lares) when you forge the letter in the
         2849 new camp and then give it to Diego. You can still join both camps after this.</p>
         2850 
         2851 
         2852 <h3>Fighting skeleton mages and their skeletons</h3>
         2853 <p>An easy way to get more experience is to let the skeleton mages summon as
         2854 much skeletons as they can. After you have defeated all of them: kill the
         2855 skeleton mage.</p>
         2856 
         2857 
         2858 <h3>Permanent str/dex/mana/hp potions/items and teachers</h3>
         2859 <p>When you want to get the maximum power at the end of the game you should
         2860 save up the items that give you a permanent boost. Teachers of strength,
         2861 dexterity and mana won't train over 100 of each skill.  However using potions
         2862 and quest rewards you can increase this over 100.</p>
         2863 
         2864 <p>You should also look out for the following:</p>
         2865 <ul>
         2866         <li>Learn to get extra force into your punch from Horatio (strength +5, this
         2867             can't be done after level 100 strength).</li>
         2868         <li>Smoke the strongest non-quest joint (+2 mana).</li>
         2869 </ul>
         2870 
         2871 
         2872 <h3>Permanent potions in Sleeper temple</h3>
         2873 <p>This one is really obvious, but I would like to point out the mummy's on
         2874 each side where Xardas is located have lots and I mean lots of permanent
         2875 potions.  This will give you a nice boost before the end battle.</p>
         2876 
         2877 
         2878 <h3>Permanent potions as reward in quests</h3>
         2879 <p>Always pick the permanent potion as a reward for quests when you can, for
         2880 example the quest for delivering the message to the High Fire magicians (mana
         2881 potion) or the one for fetching the almanac for the sect camp.  Don't forget to
         2882 pick up the potions from Riordian the water magician when you're doing the
         2883 focus stones quest, it contains a strength and dexterity potion (+3).</p>
         2884 
         2885 
         2886 <h3>In conclusion</h3>
         2887 <p>When you use the tips described above Gothic should be a really easy game
         2888 and you should be able to get at a high(er) level with lots of
         2889 mana/strength/hp.</p>
         2890 
         2891 <p>Have fun!</p>
         2892 ]]></content>
         2893 </entry>
         2894 </feed>