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 < ~/.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<TAB>type<TAB>value<LF></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&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&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 > <b>b</b>
592 Starting sector: [1024]
593 Size ('*' for entire disk): [8576] <b>*</b>
594 > <b>r</b>
595 Total free sectors: 1168.
596 > <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 > <b>w</b>
601 > <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 > 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 > 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 > 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 &&
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 &&
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 <thead>
1371 for the column headers (<td> or <th>) and <tbody> element for the data. The
1372 minimal code needed for a working datatable:
1373 </p>
1374
1375 <pre><code><html>
1376 <body>
1377 <input class="filter-text" /><!-- optional -->
1378 <table class="datatable">
1379 <thead><!-- columns -->
1380 <tr><td>Click me</td></tr>
1381 </thead>
1382 <tbody><!-- data -->
1383 <tr><td>a</td></tr>
1384 <tr><td>b</td></tr>
1385 </tbody>
1386 </table>
1387 <script type="text/javascript" src="datatable.js"></script>
1388 <script type="text/javascript">var datatables = datatable_autoload();</script>
1389 </body>
1390 </html>
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_<typename>(). 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_<customname>().
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><tfoot> 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 "config.cfg". 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 "output".
1714
1715 -t templatesdir
1716 The templates directory, the default is "templates".
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/<templatename>/header.ext
1728 templates/<templatename>/item.ext
1729 templates/<templatename>/footer.ext
1730
1731 The following filename prefixes are detected for template blocks and
1732 processed in this order:
1733
1734 "header."
1735 Header block.
1736
1737 "item."
1738 Item block.
1739
1740 "footer."
1741 Footer block.
1742
1743 The files are saved as output/<templatename>, 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 (".") are ignored.
1748
1749 The "page" 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 ".html".
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: < to the entity &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 <article>
1793 <header>
1794 <h1><a href="">${title}</a></h1>
1795 <p>
1796 <strong>Last modification on </strong>
1797 <time datetime="${updated}">${updated}</time>
1798 </p>
1799 </header>
1800 %{contentfile}
1801 </article>
1802
1803 EXIT STATUS
1804 The saait utility exits 0 on success, and >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 (".cfg" in this case) replaced to ".html".
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 '*.cfg' -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 <hiltjo@codemadness.org></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'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<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<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 < 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>