summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/images/EFF.pngbin696 -> 0 bytes
-rw-r--r--content/images/FSF.pngbin893 -> 0 bytes
-rw-r--r--content/images/FSF.svg34
-rw-r--r--content/images/GNU.pngbin853 -> 0 bytes
-rw-r--r--content/images/glider-yellow.pngbin225 -> 0 bytes
-rw-r--r--content/posts/2021-07-29-option-parsing-on-a-budget.md102
-rw-r--r--content/projects/aoc2021-bigboys.md192
-rw-r--r--content/projects/battd.md47
-rw-r--r--content/style.css136
-rw-r--r--content/style.scss152
-rwxr-xr-xgenerate.py17
-rw-r--r--meta.py2
-rw-r--r--templates/blog.html5
-rw-r--r--templates/default.html7
-rw-r--r--templates/index.html2
-rw-r--r--templates/project.html2
16 files changed, 497 insertions, 201 deletions
diff --git a/content/images/EFF.png b/content/images/EFF.png
deleted file mode 100644
index 9701d8e..0000000
--- a/content/images/EFF.png
+++ /dev/null
Binary files differ
diff --git a/content/images/FSF.png b/content/images/FSF.png
deleted file mode 100644
index c7cb606..0000000
--- a/content/images/FSF.png
+++ /dev/null
Binary files differ
diff --git a/content/images/FSF.svg b/content/images/FSF.svg
deleted file mode 100644
index e3f8d47..0000000
--- a/content/images/FSF.svg
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- version="1.0"
- width="1115.9464"
- height="490.18243"
- id="svg2434">
- <defs
- id="defs2436" />
- <g
- transform="translate(232.25893,-284.41382)"
- id="layer1">
- <g
- transform="matrix(1.24994,0,0,1.24994,-232.25893,280.59622)"
- id="g5"
- style="fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4">
- <clipPath
- id="aiclp1">
- <path
- d="M 0,0 L 3390.47,0 L 3390.47,395.159 L 0,395.159 L 0,0 z"
- id="path8" />
- </clipPath>
- <g
- id="g10">
- <path
- d="M 86.4,193.619 L 0,193.619 L 0,128.819 L 86.4,128.819 L 86.4,78.419 L 72,78.419 L 72,42.419 L 86.4,42.419 L 86.4,28.019 L 122.4,28.019 L 122.4,42.419 L 338.4,42.419 C 398.068,11.152 468.102,5.081 528.635,4.336 C 595.448,3.478 598.91,4.229 626.165,4.424 C 741.533,5.283 749.485,5.792 765.768,3.223 C 772.332,2.142 779.531,6.483 780.1,9.718 C 781.423,16.89 766.474,25.196 761.858,26.659 C 747.507,31.214 721.815,33.275 651.929,37.307 L 650.265,37.341 C 539.276,47.821 477.012,73.988 460.922,81.476 C 397.281,111.179 390.411,125.007 398.685,133.831 C 407.453,143.189 456.997,122.605 481.292,115.667 C 529.574,101.893 558.027,115.084 576,128.819 L 619.2,128.819 L 619.2,121.619 L 648,121.619 L 648,128.819 L 892.8,128.819 L 892.8,193.619 L 648,193.619 L 648,244.02 L 856.8,244.02 L 856.8,280.02 L 648,280.02 L 648,395.219 L 619.2,395.219 L 619.2,280.02 L 604.8,280.02 L 604.8,244.02 L 619.2,244.02 L 619.2,193.619 L 604.8,193.619 C 604.551,219.088 597.091,242.438 589.952,252.057 C 523.32,341.562 221.084,353.077 127.459,354.605 C 103.834,355.01 86.923,351.047 86.4,344.818 M 253.773,127.251 C 257.812,110.263 269.098,92.953 282.619,78.547 L 124.419,79.178 L 123.845,129.016 L 252.962,129.54 L 253.572,130.573 M 751.955,11.815 C 750.31,10.996 666.288,15.679 661.564,15.25 C 656.841,14.82 606.225,15.545 578.474,14.82 C 545.624,13.961 511.15,14.854 479.065,17.826 C 446.645,20.832 413.151,30.923 385.455,42.517 C 359.107,53.548 332.851,67.422 312.24,83.74 C 301.685,92.094 293.661,101.373 286.476,112.726 C 278.317,125.607 274.384,140.322 279.819,152.661 C 285.678,165.945 298.781,171.829 315.031,174.346 C 329.785,176.64 347.881,175.419 359.475,177.781 C 366.359,179.183 377.658,181.035 378.369,187.658 C 379.013,193.669 368.163,203.721 363.125,206.121 C 353.678,210.631 341.01,206.766 328.772,204.189 C 320.337,202.418 307.819,198.311 300.001,194.741 C 294.722,192.327 289.074,190.421 288,190.421 C 287.572,190.421 122.187,189.993 122.4,190.421 C 122.4,193.212 122.187,327.981 122.4,334.421 C 122.635,341.533 147.178,339.426 162.376,337.95 C 191.737,335.077 222.278,331.508 251.908,327.215 C 268.85,324.759 286.805,321.578 303.866,318.196 C 330.919,312.83 363.267,305.314 376.718,301.019 C 410.36,290.285 445.142,280.838 476.918,267.097 C 491.204,260.924 508.265,253.141 519.86,245.196 C 532.218,236.728 545.409,225.014 550.992,212.991 C 557.191,199.639 559.089,183.563 552.709,168.976 C 546.698,155.235 530.165,142.998 515.78,140.635 C 507.593,139.293 501.18,138.488 493.236,139.132 C 484.098,139.87 468.545,143.211 458.239,144.5 C 441.297,146.62 421.39,149.633 404.777,147.077 C 393.613,145.358 376.007,130.974 382.233,114.227 C 386.796,101.948 404.475,89.347 415.083,82.451 C 440.848,65.703 487.197,51.083 526.945,41.656 C 560.438,33.713 607.458,27.271 647.179,26.842 C 651.009,26.802 686.892,24.393 690.549,24.265 C 750.881,22.118 752.813,12.242 751.955,11.813"
- id="path12"
- style="fill:#b11107;stroke:none" />
- </g>
- </g>
- </g>
-</svg>
diff --git a/content/images/GNU.png b/content/images/GNU.png
deleted file mode 100644
index 5382e18..0000000
--- a/content/images/GNU.png
+++ /dev/null
Binary files differ
diff --git a/content/images/glider-yellow.png b/content/images/glider-yellow.png
deleted file mode 100644
index 4edeca1..0000000
--- a/content/images/glider-yellow.png
+++ /dev/null
Binary files differ
diff --git a/content/posts/2021-07-29-option-parsing-on-a-budget.md b/content/posts/2021-07-29-option-parsing-on-a-budget.md
new file mode 100644
index 0000000..eb323e1
--- /dev/null
+++ b/content/posts/2021-07-29-option-parsing-on-a-budget.md
@@ -0,0 +1,102 @@
+$title "Option Parsing On a Budget"
+$tags C information
+
+Recently I was writing a little code generation utility which took lots of
+positional arguments. I wanted to add two optional features to this utility,
+these options would take no arguments. I decided to use `getopt` but realised
+that this would make the code depend on POSIX, I liked the idea of staying
+dependency free so I quickly investigated really simple solutions for option
+parsing (without compromises) which would be equivalent to POSIX and GNU
+`getopt`.
+
+$pre
+
+The first iteration of the code used `getopt`, this was some pretty standard
+`getopt` code. Very portable to all systems which implement the basic POSIX
+`getopt`.
+
+```.c
+while (c = getopt(argc, argv, "dl"), c != -1) {
+ switch (c) {
+ case 'd': des_init = true; break;
+ case 'l': comp_lit = true; break;
+ case '?': usage();
+ default: assert("Option not implemented" == NULL);
+ }
+}
+```
+
+My first attempt at replacing this code looked similar to the following:
+
+```.c
+int opti;
+for (opti = 1; argv[opti] != NULL && argv[opti][0] == '-'; opti++) {
+ if (strcmp(argv[opti], "--") == 0) {
+ opti++;
+ break;
+ }
+ for (const char *opt = &argv[opti][1]; *opt != '\0'; opt++) {
+ switch (*opt) {
+ case 'd': des_init = true; break;
+ case 'l': comp_lit = true; break;
+ default:
+ fprintf(stderr, "%s unknown option -- %c\n", argv0, *opt);
+ usage();
+ }
+ }
+}
+```
+
+This replacement was POSIX `getopt` compliant in that it parsed options until it
+hit `--` or until the first non-option argument. This replacement was twice as
+long as the `getopt` version but did meant that the code no longer relied on
+POSIX. The `opti` variable had the same purpose as `optind` in getopt style
+code.
+
+I would have been happy with this version but I noticed that my program did not
+actually permit any arguments beginning with `-` and I was also up for the
+challenge. That being said, I don't think handling this is an essential feature.
+
+The final version, after a few unreadable iterations ended up being only 21
+lines long. This version handles mixed positional and optional arguments by
+relying on the C standard which allows modification of `argv`. Additionally,
+this version made code which followed it more readable than the getopt version.
+It really seems like a win win.
+
+```.c
+bool opts_end = false;
+argc = 0;
+for (int i = 1; argv[i] != NULL; i++) {
+ if (opts_end || argv[i][0] != '-') {
+ argv[argc++] = argv[i];
+ continue;
+ }
+ if (strcmp(argv[i], "--") == 0) {
+ opts_end = true;
+ continue;
+ }
+ for (const char *opt = &argv[i][1]; *opt != '\0'; opt++) {
+ switch (*opt) {
+ case 'd': des_init = true; break;
+ case 'l': comp_lit = true; break;
+ default:
+ fprintf(stderr, "%s: unknown option -- %c\n", argv0, *opt);
+ usage();
+ }
+ }
+}
+```
+
+That being said, implementing mixed options and non-options could be considered
+a misfeature. It can cause unexpected problems more often than it solves them.
+Additionally, although GNU `getopt` does this, modifying `argv` is considered by
+some to be a bit of a dirty trick. But, as mentioned before, positional
+arguments in this particular codebase could not start with a hyphen, and
+implementing this feature seemed like a fun task.
+
+Obviously this code does not handle option arguments, that's because I didn't
+have a need for those. In the case that I needed option arguments I would likely
+have gone with `arg.h` or `getopt`.
+
+As a final note, the code in this post is taken from a MIT licensed codebase,
+and should be published as part of [pack](https://the-tk.com/cgit/pack) shortly.
diff --git a/content/projects/aoc2021-bigboys.md b/content/projects/aoc2021-bigboys.md
new file mode 100644
index 0000000..da522b5
--- /dev/null
+++ b/content/projects/aoc2021-bigboys.md
@@ -0,0 +1,192 @@
+$name AOC 2021 Big Inputs (Big Boys)
+
+Big inputs for Advent of Code 2021 puzzles.
+
+$desc
+
+[TOC]
+
+If you have a problem with the naming scheme, rename it on your machine.
+
+If you see any mistakes and want to tell me, my email is at the bottom of this
+page.
+
+I will be publishing all the generators once I find a moment to clean them up.
+
+## Day 3
+
+* 1000001 lines each with a 100 bit number
+ [Download 3-1000001-100.in.xz (14MiB compressed / 97MiB decompressed)][3-1000001-100.in.xz]
+ <div class="codehilite"><pre><code>Part 1: 386463119445733053722557199393548794069517420395751036911156
+Part 2: 356913958942791247617705918285570893096041618195840162127310</code></pre></div>
+
+## Day 4
+
+* 900 numbers and 900 boards each 15x15 cells in size
+ [Download 4-900-15.in.xz (308KiB compressed / 796KiB decompressed)][4-900-15.in.xz]
+ Part 1: 22010880
+ Part 2: 5371020
+* 3600 numbers and 3600 boards each 30x30 cells in size
+ [Download 4-3600-30.in.xz (5.6MiB compressed / 16MiB decompressed)][4-3600-30.in.xz]
+ Part 1: 1527513658
+ Part 2: 199953180
+
+## Day 5
+
+* 20000 vents on a 6400x6400 field
+ [Download 5-20000-6400.in.xz (160KiB compressed / 436KiB decompressed)][5-20000-6400.in.xz]
+ Part 1: 6530681
+ Part 2: 9039258
+* 50000 vents on a 10000x10000 field
+ [Download 5-50000-10000.in.xz (404KiB compressed / 1.1MiB decompressed)][5-50000-10000.in.xz]
+ Part 1: 30405812
+ Part 2: 39512010
+* 50000 vents on a 10000000x10000000 field
+ [Download 5-50000-10000000.in.xz (660KiB compressed / 1.7MiB decompressed)][5-50000-10000000.in.xz]
+ Part 1: 72068735
+ Part 2: 113830179
+ Note: This should take under a minute in total with a compiled language.
+
+## Day 6
+
+* The example sequence `3,4,3,1,2` after 9999999 cycles
+ Solution: 378346 digits 4182599183...6707352532
+* The example sequence `3,4,3,1,2` after 67108864 (2^26) cycles
+ Solution: 2539031 digits 3060363545...5483141435
+ Note: This should take under a minute.
+
+## Day 7
+
+* 1000000 crabs
+ [Download 7-1000000-2.in.xz (3.1MiB compressed / 7.2MiB decompressed)][7-1000000-2.in.xz]
+ Part 1: 348121442862
+ Part 2: 97051441111920642
+ Note: This should be doable in under a second.
+
+## Day 8
+
+* 100000 entries
+ [Download 8-100000.in.xz (2.8MiB compressed / 8.1MiB decompressed)][8-100000.in.xz]
+ Part 1: 159946
+ Part 2: 498570828
+ Note: This should be doable in under a second (language dependant).
+
+## Day 9
+
+* 4096x4096 with a different basin forming algorithm than the original (I
+ honestly don't know exactly how the original works, but I think mine produces
+ harder basins)
+ [Download 9-4096-4.in.xz (4.3MiB compressed / 17MiB decompressed)][9-4096-4.in.xz]
+ Part 1: 152649
+ Part 2: 101367520960
+ Note: This should be doable in under a second.
+* broken 4096x4096 - There are basins with multiple local minima.
+ [Download 9-4096-2.in.xz (4.3MiB compressed / 17MiB decompressed)][9-4096-2.in.xz]
+ Part 1: 149706
+ Part 2: 4971158490375 (5292585633483 if you count duplicate basins)
+
+## Day 10
+
+* 10000 lines each with a pre-mangled length target of 1000 characters
+ [Download 10-10000-1000.in.xz (3.1MiB compressed / 9.2MiB decompressed)][10-10000-1000.in.xz]
+ <div class="codehilite"><pre><code>Part 1: 32852823
+Part 2: 105721020868542718163333508098695965856824383141538359
+Part 2 % 2^64: 11022194402702354999
+Part 2 % 2^32: 1113549367</code></pre></div>
+
+* 10000 lines each with a pre-mangled length target of 10000 characters
+ [Download 10-10000-10000.in.xz (30MiB compressed / 92MiB decompressed)][10-10000-10000.in.xz]
+ <div class="codehilite"><pre><code>Part 1: 32256063
+Part 2: 4147221136278686118851251078439942241593032865422495540589075652007224217627158672406548941332753773231145137591607755327259751330408129749234363801432056312168742919300272994666758197001661058825916005929107429822715605939942443473451119156732403958992327362236310858256528168096490885509843074970456349764872605113646021900154182133457634302249036648560726381663678169920580181158091185711536415744289810493158025390014526746339533063857301193312008845372928578055750021478792579394195467723166421532710570596861139275905662620238
+Part 2 % 2^64: 4019508546077889102
+Part 2 % 2^32: 4104032846</code></pre></div>
+
+## Day 11
+
+* 100x100 octopi
+ [Download 11-100-2.in.xz (8.0KiB compressed / 12KiB decompressed)][11-100-2.in.xz]
+ Part 1: 155620
+ Part 2: 202
+* 1000x1000 octopi
+ [Download 11-1000-2.in.xz (412KiB compressed / 980KiB decompressed)][11-1000-2.in.xz]
+ Part 1: 15030707
+ Part 2: 454
+
+## Day 12
+
+* 18 small caves, 9 big caves, maximum of 7 caves connected to any given one
+ [Download 12-18-9-7.in (240B uncompressed)][12-18-9-7.in]
+ Part 1: 617617055
+ Part 2: 51532272174
+* 18 small caves, 10 big caves, maximum of 7 caves connected to any given one
+ [Download 12-18-10-7-2.in (382B uncompressed)][12-18-10-7-2.in]
+ Part 1: 63130821975168
+ Part 2: 9781700422939493
+* 21 small caves, 12 big caves, maximum of 7 caves connected to any given one
+ [Download 12-21-12-7.in (352B uncompressed)][12-21-12-7.in]
+ Part 1: 29474222813529
+ Part 2: 5141038157763320
+* 24 small caves, 14 big caves, maximum of 7 caves connected to any given one
+ [Download 12-24-14-7.in (446B uncompressed)][12-24-14-7.in]
+ Part 1: 154850773837774189
+ Part 2: 33501351222065201672
+ Part 2 % 2^64: 15054607148355650056
+
+## Day 14
+
+[Download 14.in (822B uncompressed)][14.in]
+
+* Iterated 100000 times
+ Solution: 30104 digits 2058072250...8302987714
+ Solution % 2^64: 3612905615560025538
+ Solution % 2^32: 4000851394
+* Iterated 200000 times
+ Solution: 60207 digits 2056018485...9950238903
+ Solution % 2^64: 1164363483496783031
+ Solution % 2^32: 1329798327
+* Iterated 1000000 times
+ Solution: 301031 2039661977...9465801772
+ Solution % 2^64: 15865429992962593836
+ Solution % 2^32: 459084844
+
+## Day 15
+
+* 1000x1000 cave map
+ [Download 15-1000.in.xz (412KiB compressed / 980KiB decompressed)][15-1000.in.xz]
+ Part 1: 5576
+ Part 2: 27759
+* 10000x10000 cave map
+ [Download 15-10000.in.xz (41MiB compressed / 96MiB decompressed)][15-10000.in.xz]
+ Part 1: 55502
+ Part 2: 277236
+
+## Day 17
+
+* `target area: x=117..7310, y=-9546..-89`
+ Part 1: 45558285
+ Part 2: 69665558
+* `target area: x=50842..144383, y=-187041..-90458`
+ Part 1: 17492074320
+ Part 2: 12490271023
+
+[3-1000001-100.in.xz]: https://the-tk.com/files/aoc2021-bigboys/3-1000001-100.in.xz
+[4-900-15.in.xz]: https://the-tk.com/files/aoc2021-bigboys/4-900-15.in.xz
+[4-3600-30.in.xz]: https://the-tk.com/files/aoc2021-bigboys/4-3600-30.in.xz
+[5-20000-6400.in.xz]: https://the-tk.com/files/aoc2021-bigboys/5-20000-6400.in.xz
+[5-50000-10000.in.xz]: https://the-tk.com/files/aoc2021-bigboys/5-50000-10000.in.xz
+[5-50000-10000000.in.xz]: https://the-tk.com/files/aoc2021-bigboys/5-50000-10000000.in.xz
+[7-1000000-2.in.xz]: https://the-tk.com/files/aoc2021-bigboys/7-1000000-2.in.xz
+[8-100000.in.xz]: https://the-tk.com/files/aoc2021-bigboys/8-100000.in.xz
+[9-4096-2.in.xz]: https://the-tk.com/files/aoc2021-bigboys/9-4096-2.in.xz
+[9-4096-4.in.xz]: https://the-tk.com/files/aoc2021-bigboys/9-4096-4.in.xz
+[10-10000-1000.in.xz]: https://the-tk.com/files/aoc2021-bigboys/10-10000-1000.in.xz
+[10-10000-10000.in.xz]: https://the-tk.com/files/aoc2021-bigboys/10-10000-10000.in.xz
+[11-100-2.in.xz]: https://the-tk.com/files/aoc2021-bigboys/11-100-2.in.xz
+[11-1000-2.in.xz]: https://the-tk.com/files/aoc2021-bigboys/11-1000-2.in.xz
+[12-18-9-7.in]: https://the-tk.com/files/aoc2021-bigboys/12-18-9-7.in
+[12-18-10-7-2.in]: https://the-tk.com/files/aoc2021-bigboys/12-18-10-7-2.in
+[12-21-12-7.in]: https://the-tk.com/files/aoc2021-bigboys/12-21-12-7.in
+[12-24-14-7.in]: https://the-tk.com/files/aoc2021-bigboys/12-24-14-7.in
+[14.in]: https://the-tk.com/files/aoc2021-bigboys/14.in
+[15-1000.in.xz]: https://the-tk.com/files/aoc2021-bigboys/15-1000.in.xz
+[15-10000.in.xz]: https://the-tk.com/files/aoc2021-bigboys/15-10000.in.xz
diff --git a/content/projects/battd.md b/content/projects/battd.md
new file mode 100644
index 0000000..3e156cb
--- /dev/null
+++ b/content/projects/battd.md
@@ -0,0 +1,47 @@
+$name battd
+$source https://the-tk.com/cgit/battd/
+
+battd is a simple battery daemon written for use with a daemontools-style
+supervisor.
+
+$desc
+
+The daemon `run` script polls the status of a user defined `check` function
+every `long_interval` or `short_interval` seconds. The interval is determined by
+the status of the `interval` function. On the transition from a successful
+`check` exit status to an unsuccessful `check` exit status the `failed` function
+is called. These functions and optionally the variables `long_interval` and
+`short_interval` need to be provided in a `conf` file located in the same
+directory as the script.
+
+The following `conf` file contains an example configuration which increases the
+polling interval from 5 minutes to 30 seconds when the battery level is below 16
+percent or fewer than 20 minutes of battery life remain and puts the machine in
+a hybrid sleep once the battery level is below 8 percent or fewer than 10
+minutes of battery life remain.
+
+```sh
+battery=/sys/class/power_supply/BAT0/uevent
+interval() { ./battcheck min_time=1200 min_pct=16 "$battery"; }
+check() { ./battcheck min_time=600 min_pct=8 "$battery"; }
+failed() { zzz -H; }
+```
+
+Finally, the `battcheck` awk script takes two optional command line variable
+assignments for `min_pct` and `min_time` specifying the remaining battery
+percentage and remaining battery time in seconds respectively after which the
+script will produce an unsuccessful exit code.
+
+These files should be placed inside a service directory making sure that `run`
+and `battcheck` are both executable. The service handles SIGHUP to reload its
+configuration at runtime.
+
+The `battcheck` script is quite versatile and may be useful in other contexts, in
+which case it is recommended to install it to `/usr/local/sbin` or another
+appropriate location.
+
+If the script crashes before a success to failure transition of the `check`
+function and is re-started after the transition then the script will incorrectly
+ignore this transition and not call the `failed` function. This could be fixed
+by storing the previous status in on a temporary file system but this was not
+done due to the unlikelihood of the event and in order to keep the code simple.
diff --git a/content/style.css b/content/style.css
new file mode 100644
index 0000000..53e096c
--- /dev/null
+++ b/content/style.css
@@ -0,0 +1,136 @@
+html {
+ background-image: url(./images/grid_noise.png);
+ background-repeat: repeat;
+ background-color: #F3F5F7;
+ font-family: sans-serif;
+ text-align: justify;
+}
+
+main {
+ max-width: 100%;
+ width: 50em;
+ margin: 1em auto;
+ padding: 1em;
+ background-color: white;
+ box-shadow: 0 0 5px #888;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+#copyright {
+ color: grey;
+ font-size: x-small;
+ text-align: center;
+}
+
+nav {
+ overflow: hidden;
+ width: 100%;
+ font-weight: bold;
+ font-size: large;
+}
+nav a {
+ text-decoration: none;
+}
+nav a:link {
+ color: black;
+}
+nav a:visited {
+ color: black;
+}
+nav a:hover {
+ color: grey;
+}
+nav a:active {
+ color: darkgrey;
+}
+
+div.codehilite pre {
+ border: 1px dashed #DDD;
+ background-color: #FAFAFA;
+ padding: 0.1em;
+}
+
+div.codehilite pre {
+ display: block;
+ overflow: auto;
+}
+
+.fleft {
+ float: left;
+}
+
+.fright {
+ float: right;
+}
+
+figure {
+ margin: 0 0.5em;
+}
+figure figcaption {
+ font-size: small;
+ color: #BBB;
+ text-align: right;
+ border-top: thin dotted grey;
+}
+
+blockquote {
+ font-family: serif;
+}
+
+img.icon {
+ height: 0.8em;
+}
+
+a:link {
+ color: grey;
+}
+
+a:hover {
+ color: lightgrey;
+}
+
+a:visited {
+ color: darkgrey;
+}
+
+a:active {
+ color: darkgrey;
+}
+
+footer {
+ text-align: center;
+}
+
+hr {
+ border: none;
+ border-top: 1px dashed lightgrey;
+ height: 0px;
+}
+
+article footer {
+ text-align: right;
+}
+
+time {
+ color: #BBB;
+}
+
+ul.taglist {
+ padding-left: 0;
+ list-style: none;
+}
+ul.taglist li {
+ display: inline;
+}
+
+ul.postlist {
+ padding-left: 0;
+ list-style: none;
+}
+
+ul.projects {
+ padding-left: 0;
+ list-style: none;
+}
diff --git a/content/style.scss b/content/style.scss
deleted file mode 100644
index 2c80e91..0000000
--- a/content/style.scss
+++ /dev/null
@@ -1,152 +0,0 @@
-html {
- background-image: url(./images/grid_noise.png);
- background-repeat: repeat;
- background-color: #F3F5F7;
- font-family: sans-serif;
- text-align: justify;
-}
-
-main {
- max-width: 100%;
- width: 50em;
- margin: 1em auto;
- padding: 1em;
- background-color: white;
- box-shadow: 0 0 5px #888;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-#copyright {
- color: grey;
- font-size: x-small;
- text-align: center;
-}
-
-nav {
- overflow: hidden; width: 100%; font-weight: bold; font-size: large;
- a { text-decoration: none; }
- a:link { color: black; }
- a:visited { color: black; }
- a:hover { color: grey; }
- a:active { color: darkgrey; }
-}
-
-code, div.codehilite pre {
- border: 1px dashed #DDD;
- background-color: #FAFAFA;
- padding: 0.1em;
-}
-div.codehilite pre { display: block; overflow: auto; }
-
-.fleft { float: left; }
-.fright { float: right; }
-
-figure {
- margin: 0 0.5em;
- figcaption {
- font-size: small;
- color: #BBB;
- text-align: right;
- border-top: thin dotted grey;
- }
-}
-
-blockquote { font-family: serif; }
-
-img.icon { height: 0.8em; }
-
-a:link { color: grey; } a:hover { color: lightgrey; }
-a:visited { color: darkgrey; } a:active { color: darkgrey; }
-
-footer { text-align: center; }
-
-hr { border: none; border-top: 1px dashed lightgrey; height: 0px; }
-
-article footer {
- text-align: right;
-}
-
-time {
- color: #BBB;
-}
-
-ul.taglist {
- padding-left: 0;
- list-style: none;
- li { display: inline; }
-}
-
-ul.postlist {
- padding-left: 0;
- list-style: none;
-}
-
-ul.projects {
- padding-left: 0;
- list-style: none;
-}
-
-/* Syntax highlighting mess */
-.codehilite {
- .c { color: #998; font-style: italic }
- .err { color: #a61717; background-color: #e3d2d2 }
- .k { font-weight: bold }
- .o { font-weight: bold }
- .cm { color: #998; font-style: italic }
- .cp { color: #999; font-weight: bold }
- .c1 { color: #998; font-style: italic }
- .cs { color: #999; font-weight: bold; font-style: italic }
- .gd { color: #000; background-color: #fdd }
- .gd .x { color: #000; background-color: #faa }
- .ge { font-style: italic }
- .gr { color: #a00 }
- .gh { color: #999 }
- .gi { color: #000; background-color: #dfd }
- .gi .x { color: #000; background-color: #afa }
- .go { color: #888 }
- .gp { color: #555 }
- .gs { font-weight: bold }
- .gu { color: #aaa }
- .gt { color: #a00 }
- .kc { font-weight: bold }
- .kd { font-weight: bold }
- .kp { font-weight: bold }
- .kr { font-weight: bold }
- .kt { color: #458; font-weight: bold }
- .m { color: #099 }
- .s { color: #d14 }
- .na { color: #008080 }
- .nb { color: #0086B3 }
- .nc { color: #458; font-weight: bold }
- .no { color: #008080 }
- .ni { color: #800080 }
- .ne { color: #900; font-weight: bold }
- .nf { color: #900; font-weight: bold }
- .nn { color: #555 }
- .nt { color: #000080 }
- .nv { color: #008080 }
- .ow { font-weight: bold }
- .w { color: #bbb }
- .mf { color: #099 }
- .mh { color: #099 }
- .mi { color: #099 }
- .mo { color: #099 }
- .sb { color: #d14 }
- .sc { color: #d14 }
- .sd { color: #d14 }
- .s2 { color: #d14 }
- .se { color: #d14 }
- .sh { color: #d14 }
- .si { color: #d14 }
- .sx { color: #d14 }
- .sr { color: #009926 }
- .s1 { color: #d14 }
- .ss { color: #990073 }
- .bp { color: #999 }
- .vc { color: #008080 }
- .vg { color: #008080 }
- .vi { color: #008080 }
- .il { color: #099 }
-}
diff --git a/generate.py b/generate.py
index b18e1c2..a139f19 100755
--- a/generate.py
+++ b/generate.py
@@ -2,14 +2,14 @@
from collections import namedtuple, Counter
from datetime import date
-from functools import partial
from glob import glob
from itertools import chain
-from jinja2 import Environment, FileSystemLoader, Markup
+from jinja2 import Environment, FileSystemLoader
from markdown import markdown
+from markupsafe import Markup
from operator import attrgetter
from subprocess import call as run
-from sys import argv
+from pygments.formatters import HtmlFormatter
import meta
import os
@@ -25,8 +25,7 @@ ERRORS = {
504: "Gateway Timeout",
}
-md = lambda s: Markup(markdown(s, extensions=['markdown.extensions.fenced_code',
- 'markdown.extensions.codehilite']))
+md = lambda s: Markup(markdown(s, extensions=['fenced_code', 'codehilite', 'toc']))
File = namedtuple('File', 'content date slug ext')
def parse(path, has_date=False):
@@ -119,6 +118,7 @@ def main(argv=['generate.py']):
env = Environment(loader=FileSystemLoader('./templates'), autoescape=True)
env.globals['site'] = {'baseurl': baseurl}
env.filters['datefmt'] = lambda d, f='%Y-%m-%d': d.strftime(f)
+ env.filters['md'] = md
posts = glob(os.path.join(CONTENT, 'posts', '*'))
posts = [p for p in posts if not os.path.split(p)[1].startswith('_')]
@@ -129,7 +129,7 @@ def main(argv=['generate.py']):
page = {
'title': 'Blog',
'description': 'New posts will appear chronologically on this page.',
- 'keywords': ', '.join(KWORDS),
+ 'keywords': ', '.join(KWORDS | set(tags)),
'tags': tags,
'posts': posts,
}
@@ -171,7 +171,10 @@ def main(argv=['generate.py']):
}
output('error/{}.html'.format(code), env.get_template('error.html').render(page=page))
- run(['scss', os.path.join(CONTENT, 'style.scss'), os.path.join(OUTPUT, 'style.css')])
+ with open(os.path.join(OUTPUT, 'style.css'), 'w') as f:
+ with open(os.path.join(CONTENT, 'style.css')) as css:
+ f.write(css.read())
+ f.write(HtmlFormatter().get_style_defs('.codehilite'))
run(['cp', '-r', os.path.join(CONTENT, 'images'), OUTPUT])
if __name__ == '__main__':
diff --git a/meta.py b/meta.py
index 7bb948d..e550651 100644
--- a/meta.py
+++ b/meta.py
@@ -4,7 +4,7 @@ import shlex
Meta = namedtuple('Meta', ['sects', 'meta'])
def _merge(l):
- return ''.join(l).strip()
+ return ''.join(l)
def _next(l):
sect = deque()
while l and not l[0].strip().startswith('$'):
diff --git a/templates/blog.html b/templates/blog.html
index 87a9cd9..c32451b 100644
--- a/templates/blog.html
+++ b/templates/blog.html
@@ -7,4 +7,9 @@
<ul class="postlist">{% for post in page.posts %}
<li><time>{{ post.date|datefmt }}</time> | <a href="{{ '/' + post.location }}">{{ post.title }}</a>{% endfor %}
</ul>
+{% if page.tags %}
+<ul class="taglist">
+ <li>All tags:</li>{% for tag in page.tags %}
+ <li><a href="{{ '/tag/' + tag + '.html' }}">{{ tag }}</a></li>{% endfor %}
+</ul>{% endif %}
{% endblock %}
diff --git a/templates/default.html b/templates/default.html
index 07ff3ed..f6898ae 100644
--- a/templates/default.html
+++ b/templates/default.html
@@ -1,11 +1,11 @@
<!DOCTYPE html>
-<html>
+<html lang="en-GB">
<head>
+ <meta charset="utf-8" />
<title>{{ page.title }}</title>
<link rel="stylesheet" href="/style.css" />
<link rel="icon" type="image/png" sizes="32x32" href="/images/icon32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/images/icon16x16.png" />
- <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="{{ page.description }}" />
<meta name="author" content="Tomasz Kramkowski <tk@the-tk.com>" />
@@ -29,9 +29,6 @@
• <a href="https://github.com/EliteTK">github</a>
• <a href="https://the-tk.com/cgit">cgit</a>
• <a href="https://the-tk.com/archive">ML archive</a>
- • <a href="http://www.catb.org/hacker-emblem/"><img class="icon" src="/images/glider-yellow.png" alt="Hacker Emblem" /></a>
- • <a href="https://www.eff.org/"><img class="icon" src="/images/EFF.png" alt="EFF Logo" /></a>
- • <a href="https://www.fsf.org/"><img class="icon" src="/images/GNU.png" alt="GNU Logo" /></a>
</footer>
</main>
<div id="copyright">
diff --git a/templates/index.html b/templates/index.html
index c32a7fb..6a64d79 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -11,7 +11,7 @@
<header>
<h3>{{ post.title }}</h3>
</header>
- {{ post.pre }}
+ {{ post.pre|md }}
<a href="/{{ post.location }}">Read more...</a>
<footer>
<time>{{ post.date|datefmt }}</time>
diff --git a/templates/project.html b/templates/project.html
index 15e4d9a..2246296 100644
--- a/templates/project.html
+++ b/templates/project.html
@@ -2,7 +2,7 @@
{% block content %}
<h1>{{ page.title }}</h1>
{{ page.content }}
-{% if page.source or page.ml %}<hr />
+{% if page.source or page.ml or page.aur %}<hr />
<dl>
{% if page.source %}<dt>Source</dt>
<dd><a href="{{ page.source }}">{{ page.source }}</a></dd>{% endif %}