diff options
-rw-r--r-- | content/images/EFF.png | bin | 696 -> 0 bytes | |||
-rw-r--r-- | content/images/FSF.png | bin | 893 -> 0 bytes | |||
-rw-r--r-- | content/images/FSF.svg | 34 | ||||
-rw-r--r-- | content/images/GNU.png | bin | 853 -> 0 bytes | |||
-rw-r--r-- | content/images/glider-yellow.png | bin | 225 -> 0 bytes | |||
-rw-r--r-- | content/posts/2021-07-29-option-parsing-on-a-budget.md | 102 | ||||
-rw-r--r-- | content/projects/aoc2021-bigboys.md | 192 | ||||
-rw-r--r-- | content/projects/battd.md | 47 | ||||
-rw-r--r-- | content/style.css | 136 | ||||
-rw-r--r-- | content/style.scss | 152 | ||||
-rwxr-xr-x | generate.py | 17 | ||||
-rw-r--r-- | meta.py | 2 | ||||
-rw-r--r-- | templates/blog.html | 5 | ||||
-rw-r--r-- | templates/default.html | 7 | ||||
-rw-r--r-- | templates/index.html | 2 | ||||
-rw-r--r-- | templates/project.html | 2 |
16 files changed, 497 insertions, 201 deletions
diff --git a/content/images/EFF.png b/content/images/EFF.png Binary files differdeleted file mode 100644 index 9701d8e..0000000 --- a/content/images/EFF.png +++ /dev/null diff --git a/content/images/FSF.png b/content/images/FSF.png Binary files differdeleted file mode 100644 index c7cb606..0000000 --- a/content/images/FSF.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 5382e18..0000000 --- a/content/images/GNU.png +++ /dev/null diff --git a/content/images/glider-yellow.png b/content/images/glider-yellow.png Binary files differdeleted file mode 100644 index 4edeca1..0000000 --- a/content/images/glider-yellow.png +++ /dev/null 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__': @@ -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 %} |