From c34ae6fed8503c6f8b27b4bd55cf26bb3f47ad23 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Wed, 18 Jul 2018 23:46:06 +0100 Subject: init commit --- .gitignore | 4 + content/images/EFF.png | Bin 0 -> 696 bytes content/images/FSF.png | Bin 0 -> 893 bytes content/images/FSF.svg | 34 ++++ content/images/GNU.png | Bin 0 -> 853 bytes content/images/ccbysa.png | Bin 0 -> 428 bytes content/images/glider-yellow.png | Bin 0 -> 225 bytes content/images/grid_noise.png | Bin 0 -> 4638 bytes content/images/icon16x16.png | Bin 0 -> 553 bytes content/images/icon32x32.png | Bin 0 -> 556 bytes content/posts/2015-06-28-it_s-alive-again.md | 75 +++++++++ content/posts/2015-08-16-mystery-ds-record.md | 79 +++++++++ .../posts/2015-12-02-malloc-realloc-and-sizeof.md | 87 ++++++++++ content/posts/2016-04-04-dnssec.md | 25 +++ content/posts/2018-07-18-n900-fast-gps-fix.md | 39 +++++ content/projects/c-stuff.md | 22 +++ content/projects/dotfiles.md | 6 + content/projects/minecurses.md | 8 + content/projects/the-tk.com.md | 45 ++++++ content/projects/vav.md | 6 + content/style.scss | 153 ++++++++++++++++++ generate.py | 178 +++++++++++++++++++++ meta.py | 28 ++++ mksite.sh | 6 + output/.gitignore | 2 + serve.sh | 4 + templates/blog.html | 7 + templates/default.html | 46 ++++++ templates/error.html | 5 + templates/index.html | 22 +++ templates/post.html | 16 ++ templates/project.html | 16 ++ templates/projects.html | 11 ++ templates/tag.html | 7 + 34 files changed, 931 insertions(+) create mode 100644 .gitignore create mode 100644 content/images/EFF.png create mode 100644 content/images/FSF.png create mode 100644 content/images/FSF.svg create mode 100644 content/images/GNU.png create mode 100644 content/images/ccbysa.png create mode 100644 content/images/glider-yellow.png create mode 100644 content/images/grid_noise.png create mode 100644 content/images/icon16x16.png create mode 100644 content/images/icon32x32.png create mode 100644 content/posts/2015-06-28-it_s-alive-again.md create mode 100644 content/posts/2015-08-16-mystery-ds-record.md create mode 100644 content/posts/2015-12-02-malloc-realloc-and-sizeof.md create mode 100644 content/posts/2016-04-04-dnssec.md create mode 100644 content/posts/2018-07-18-n900-fast-gps-fix.md create mode 100644 content/projects/c-stuff.md create mode 100644 content/projects/dotfiles.md create mode 100644 content/projects/minecurses.md create mode 100644 content/projects/the-tk.com.md create mode 100644 content/projects/vav.md create mode 100644 content/style.scss create mode 100755 generate.py create mode 100644 meta.py create mode 100755 mksite.sh create mode 100644 output/.gitignore create mode 100755 serve.sh create mode 100644 templates/blog.html create mode 100644 templates/default.html create mode 100644 templates/error.html create mode 100644 templates/index.html create mode 100644 templates/post.html create mode 100644 templates/project.html create mode 100644 templates/projects.html create mode 100644 templates/tag.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..593c152 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc +*.tgz +.sass-cache +__pycache__ diff --git a/content/images/EFF.png b/content/images/EFF.png new file mode 100644 index 0000000..9701d8e Binary files /dev/null and b/content/images/EFF.png differ diff --git a/content/images/FSF.png b/content/images/FSF.png new file mode 100644 index 0000000..c7cb606 Binary files /dev/null and b/content/images/FSF.png differ diff --git a/content/images/FSF.svg b/content/images/FSF.svg new file mode 100644 index 0000000..e3f8d47 --- /dev/null +++ b/content/images/FSF.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + diff --git a/content/images/GNU.png b/content/images/GNU.png new file mode 100644 index 0000000..5382e18 Binary files /dev/null and b/content/images/GNU.png differ diff --git a/content/images/ccbysa.png b/content/images/ccbysa.png new file mode 100644 index 0000000..9c0b590 Binary files /dev/null and b/content/images/ccbysa.png differ diff --git a/content/images/glider-yellow.png b/content/images/glider-yellow.png new file mode 100644 index 0000000..4edeca1 Binary files /dev/null and b/content/images/glider-yellow.png differ diff --git a/content/images/grid_noise.png b/content/images/grid_noise.png new file mode 100644 index 0000000..30d1be4 Binary files /dev/null and b/content/images/grid_noise.png differ diff --git a/content/images/icon16x16.png b/content/images/icon16x16.png new file mode 100644 index 0000000..2c77bc3 Binary files /dev/null and b/content/images/icon16x16.png differ diff --git a/content/images/icon32x32.png b/content/images/icon32x32.png new file mode 100644 index 0000000..7ffd840 Binary files /dev/null and b/content/images/icon32x32.png differ diff --git a/content/posts/2015-06-28-it_s-alive-again.md b/content/posts/2015-06-28-it_s-alive-again.md new file mode 100644 index 0000000..ccc34a4 --- /dev/null +++ b/content/posts/2015-06-28-it_s-alive-again.md @@ -0,0 +1,75 @@ +$title "It's alive... again..." +$tags webdev + +After putting it off for a few months, and a weekend of trying to make the +perfect simple stylesheet, I finally got around to re-doing my website. It's +now simpler, easier to read and actually has a blog. + +$pre + +Initially I was going to write my own static content generator in python using +[Jinja2][jinja], pygments and docutils. I realise that doing this was going to +be a giant pain and I didn't quite have the time to actually try to make one. +I've heard about [Jekyll][jekyll] before and decided to investigate. I was +hoping it was written in python but was instead written in ruby, however, in +the end, this didn't matter. + +I was initially greeted by an _interesting_ layout and became worried that if I +went any further I would be here for the rest of the day trying to wrangle the +thing into submission. + +I started with the basics, I changed a few details in the config, this made +some text change and remove some other text so I went about exploring. I knew +Jekyll was using [Liquid][liquid] templates and having used Jinja before I knew what I +was looking for. + +I quickly discovered that `/_layouts` stored a set of "base" templates which +included a set of templates from `/_includes` to bring stuff together. This +wasn't too bad. + +I then found `/css` or more importantly `/css/main.scss`. I've never seen an +"scss" extension before but at first glance it looked a bit like CSS. At a +second glance it looked like a css generator. I didn't really need this, the +CSS for this website is in no way complex enough to warrant templating css, so +I got to work modifying the existing `_layouts` and `_includes`, and simply +copied in my usual css. + +Within about 10 minutes I had a working front page design but I noticed +something annoying; the generated HTML had about 10 line breaks in the middle +and generally looked like a mess. I realised that most of this space was +because of Liquid's tokens leaving space. After moving all the tokens around in +a way which meant that minimal breaks were introduced, I was left with +something presentable. + +But this wasn't the end of the weirdness, the next problem was that for some +reason, the indentation on the very first line of an imported template was +always correct, but subsequent indentation was broken. (I was hoping that, like +many text editors, Liquid might take the indent on the line where a block is +being pasted and copy it for every line of the block, but on second thought, +this might not be desirable for for example, `
`). I had to fix this by
+indenting all but the first line correctly in every `/_includes` template and
+this managed to cover most of the cases.
+
+In the end, after pasting the syntax highlighting from
+`/_sass/_syntax-highlighting.scss` into my stylesheet and manually "generating"
+all the required entries. I was left with this very end result you see before
+you. As a final verdict, I really do think that Jekyll is quite awesome even
+though I've probably not used it in the most efficient fashion. All things
+considered, however, this only took about an hour.
+
+Now, bask in the glory of the syntax highlighting:
+
+~~~.c
+#include 
+
+int main(void)
+{
+	puts("Colours!!!");
+
+	return 0;
+}
+~~~
+
+[jekyll]: http://jekyllrb.com
+[jinja]:  http://jinja.pocoo.org/
+[liquid]: http://liquidmarkup.org/
diff --git a/content/posts/2015-08-16-mystery-ds-record.md b/content/posts/2015-08-16-mystery-ds-record.md
new file mode 100644
index 0000000..9757503
--- /dev/null
+++ b/content/posts/2015-08-16-mystery-ds-record.md
@@ -0,0 +1,79 @@
+$title "The mystery DS record"
+$tags DNS DNSSEC
+
+So after transferring my domain from transip.eu to namecheap.com for WHOIS
+privacy I realised that suddenly the Google public DNS servers were no longer
+able to resolve my domain. Very quickly, I realised that quite a few things
+seemed to rely on the Google public DNS services (and DNSSEC supporting
+resolvers). Fun ensued.
+
+$pre
+
+DNSSEC is a fancy extension to DNS which allows resolvers to cryptographically
+confirm, through the use of some public keys and signatures, that the records
+they are looking up are in fact the records they want and not the result of
+some MITM attack. This is explained well in multiple places, so I won't explain
+it here.
+
+I transferred my domain from transip.eu who provide DNSSEC (no way to publish
+DS records, everything is maintained in the background), but don't provide
+WHOIS privacy, to namecheap.com who do provide WHOIS privacy but don't provide
+DNSSEC. The DS record that transip.eu published to gtld-servers for their
+DNSSEC was left published after I transferred which initially, for someone who
+didn't know anything about DNSSEC, caused many confusing side effects.
+
+DS records have to be published in the parent zone, this means that it has to
+be done through your registrar. (Unless you have a lot of money and time and
+feel like bribing Verisign. If someone knows how to do this without bribery,
+tell me!). Upon contacting namecheap about the issue, the person I was talking
+to seemed confused about the issue. They seemed to think I was having issues
+with A and AAAA records and DNS propagation. They tried to inform me that I
+just had to wait. Of course, all the waiting in the world wouldn't get the DS
+records to disappear so after explaining the situation a bit better (I still
+didn't quite know much about it myself) I got them to contact their "upstream
+DNS provider."
+
+Finally, a weekend later, the DS record was gone and Google's DNS servers were
+serving my records again. Additionally, I switched over to using my own BIND
+name server so I could have full control over my DNS. This proved to be quite
+fun to set up. The second server is hosted by a good friend of mine and the
+third one by a friend of that friend. So far, other than me accidentally
+forgetting to enable named.service and rebooting my server to find that DNS
+wasn't working very well, I've had no problems.
+So after transferring my domain from transip.eu to namecheap.com for WHOIS
+privacy I realised that suddenly the Google public DNS servers were no longer
+able to resolve my domain. Very quickly, I realised that quite a few things
+seemed to rely on the Google public DNS services (and DNSSEC supporting
+resolvers). Fun ensued.
+
+DNSSEC is a fancy extension to DNS which allows resolvers to cryptographically
+confirm, through the use of some public keys and signatures, that the records
+they are looking up are in fact the records they want and not the result of
+some MITM attack. This is explained well in multiple places, so I won't explain
+it here.
+
+I transferred my domain from transip.eu who provide DNSSEC (no way to publish
+DS records, everything is maintained in the background), but don't provide
+WHOIS privacy, to namecheap.com who do provide WHOIS privacy but don't provide
+DNSSEC. The DS record that transip.eu published to gtld-servers for their
+DNSSEC was left published after I transferred which initially, for someone who
+didn't know anything about DNSSEC, caused many confusing side effects.
+
+DS records have to be published in the parent zone, this means that it has to
+be done through your registrar. (Unless you have a lot of money and time and
+feel like bribing Verisign. If someone knows how to do this without bribery,
+tell me!). Upon contacting namecheap about the issue, the person I was talking
+to seemed confused about the issue. They seemed to think I was having issues
+with A and AAAA records and DNS propagation. They tried to inform me that I
+just had to wait. Of course, all the waiting in the world wouldn't get the DS
+records to disappear so after explaining the situation a bit better (I still
+didn't quite know much about it myself) I got them to contact their "upstream
+DNS provider."
+
+Finally, a weekend later, the DS record was gone and Google's DNS servers were
+serving my records again. Additionally, I switched over to using my own BIND
+name server so I could have full control over my DNS. This proved to be quite
+fun to set up. The second server is hosted by a good friend of mine and the
+third one by a friend of that friend. So far, other than me accidentally
+forgetting to enable named.service and rebooting my server to find that DNS
+wasn't working very well, I've had no problems.
diff --git a/content/posts/2015-12-02-malloc-realloc-and-sizeof.md b/content/posts/2015-12-02-malloc-realloc-and-sizeof.md
new file mode 100644
index 0000000..ee3f508
--- /dev/null
+++ b/content/posts/2015-12-02-malloc-realloc-and-sizeof.md
@@ -0,0 +1,87 @@
+$title "malloc, realloc and sizeof"
+$tags information C
+
+I spend a lot of time in ##c hoping to provide useful information to people
+wishing to learn and understand C and almost every day I see malloc and realloc
+code which appears to be straight from a horror movie. I've had to say what I
+say in this post repeatedly to many people so I've decided that it's time to
+write it once and simply give people a link every time I wish to explain why
+such code is incorrect.
+
+$pre
+
+The code I'm describing is usually a combination of some or all of this:
+
+~~~ c
+struct foo *bar;
+
+bar = (struct foo *)malloc(sizeof(struct foo) * 10);
+
+bar = (struct foo *)realloc(bar, sizeof(struct foo) * 20);
+~~~
+
+There are multiple issues with this:
+
+ - Casting malloc can hide newbie mistakes such as forgetting to include
+   stdlib.h which can in turn cause strange issues down the line.
+ - Casting unnecessarily also gives you rather long lines, especially when you
+   have a rather complicated/long type (e.g. const struct foo * const *).
+ - You're having to type the same thing three times, when you could type it
+   once.
+ - If you screw up rewriting the same thing one of three times, you might end
+   up allocating the wrong amount of space and still end up with code which
+   runs, this can be dangerous down the line if some clever person finds a way
+   to exploit this.
+ - If you ever want to change the type of bar, you need to change it in 3
+   places, if you forget to change it in one of these, you end up with the same
+   issue described in the point above.
+ - Finally (regarding just the realloc line) if realloc fails, memory is leaked
+   since bar's original value is overwritten with NULL, realloc doesn't
+   automatically free the original pointer when it can't realloc.
+
+The easy solution is simply:
+
+~~~ c
+struct foo *bar, *tmpbar;
+
+bar = malloc(sizeof *bar * 10);
+
+tmpbar = realloc(bar, sizeof *tmpbar * 20);
+
+if (!tmpbar) {
+	free(bar);
+	/* error handling */
+} else {
+	bar = tmpbar;
+}
+~~~
+
+This solves all of the outlined problems.
+
+-----------------------
+
+Here's the answers to two common questions:
+
+**Q**: _The compiler has always complained (warned) when I tried to assign a
+pointer to one type to a pointer to another type. Would this not be the case
+here?_
+
+**A**: The C standard states (C11/C99 §6.3.2.3 and C11/C99 §6.5.16.1) roughly
+that a pointer to void can be assigned to a pointer to any type, and vice
+versa, freely without issuing a warning. This in turn means that the return
+value of malloc (and any other function returning void \*) will be converted
+without warning to the desired type without needing a cast.
+
+**Q**: _What's the deal with `sizeof *bar`? Don't functions need
+brackets?_
+
+
+**A**: The sizeof operator can be given an expression as an operand as well as
+the parenthesized name of a type. This means we can do `sizeof *bar`. Also,
+since sizeof is an _operator_ and **not** a function, it doesn't require
+parentheses when its operand is an expression, the C standard does however
+require that for types, the type name has to be parenthesized.  In the end, it's
+a style choice whether the parentheses are always there or not, but personally I
+think leaving them out is more consistent. (NB: The first example uses sizeof as
+such: `sizeof(type)`, personally I prefer leaving a space between `sizeof` and
+`(type)` as I would with most other operators.)
diff --git a/content/posts/2016-04-04-dnssec.md b/content/posts/2016-04-04-dnssec.md
new file mode 100644
index 0000000..13c1d60
--- /dev/null
+++ b/content/posts/2016-04-04-dnssec.md
@@ -0,0 +1,25 @@
+$title "DNSSEC"
+$tags information DNS DNSSEC
+
+As of today my domain finally supports DNSSEC. It was much simpler than I
+thought it would be. It seems namecheap now officially allows you to publish DS
+records in the parent zone of your domain (limited only to TLDs which support
+it). This is one of the last things that I wanted to set up on my server.
+
+$pre
+
+In the end, the process was made very simple by the existence of
+[this][cheatsheet] which details exactly how to set up DNSSEC on BIND 9.10 or
+higher.
+
+Currently the KSK is SHARSA256 1024 bits and the ZSK is SHARSA256 2048 bits, I
+am considering moving to using a 2048 bit KSK but I'm not sure if there will be
+much of a benefit.  I am using NSEC3 with a SHA-1 hash with the opt-out bit
+unset and 100 iterations.
+
+In any case, you can now rest assured that if your resolver uses DNSSEC
+(Google's resolvers will return a failure in case they find a DS record but the
+DNSSEC validation fails) you will be receiving signed and verifiable data.  Of
+course, I doubt many people care.
+
+[cheatsheet]: https://kb.isc.org/getAttach/122/AA-01311/DNSSEC-QR-B4.pdf
diff --git a/content/posts/2018-07-18-n900-fast-gps-fix.md b/content/posts/2018-07-18-n900-fast-gps-fix.md
new file mode 100644
index 0000000..33d3482
--- /dev/null
+++ b/content/posts/2018-07-18-n900-fast-gps-fix.md
@@ -0,0 +1,39 @@
+$title "N900 Fast GPS Fix"
+$tags N900 GPS
+
+If anyone is, like me, still using the N900, they may have noticed that
+acquiring an initial GPS fix can take minutes. The reason for this is that even
+in the latest CSSU, supl.nokia.com no longer works as a location server. The fix
+for this is actually relatively quick and easy and will make an initial GPS fix
+take seconds rather than minutes.
+
+$pre
+
+The exact details of what needs to be done can be found in the last few posts of
+[this][tmo-thread] Maemo forum thread. The problem is that supl.nokia.com no
+longer resolves to an IP address. However, this doesn't mean that the server
+behind supl.nokia.com is no longer running. Surprisingly, it still is.
+
+The long and short of it is this:
+
+1. Make sure you have the latest CSSU and a working N900 to begin with;
+2. Go [here][certman] and download `libmaemosec-certman0_0.2.10_armel.deb`,
+   `libmaemosec0_0.2.10_armel.deb`, `maemosec-certman-common-ca_0.2.10_all.deb`,
+   and `maemosec-certman-tools_0.2.10_armel.deb`;
+3. Install the above packages via the command line as root (you'll need gainroot)
+   by using `dpkg -i` (put all the files in their own directory and use `dpkg -i
+   *` to save time);
+4. Edit `/etc/hosts` and change `supl.nokia.com` to point to `52.200.182.188`;
+5. Check it all works by running `cmcli -T common-ca -v supl.nokia.com:7275` and
+   `cmcli -T location-proxy -v supl.nokia.com:7275`, both should say "Verified
+   OK.";
+6. If this doesn't work, try `stop location-proxy` and then
+   `start location-proxy` (as root) and go back to step 5.
+
+GPS fixes should happen very quickly now. If it's the year 2023 and this didn't
+work then good luck finding a new fix, hopefully you put the details on your
+blog too. Alternatively, feel free to contact me and I might still be using the
+N900 and might know how to help.
+
+[tmo-thread]: https://talk.maemo.org/showthread.php?t=90651
+[certman]:    http://maemo.merlin1991.at/cssu/community-devel/pool/free/m/maemo-security-certman
diff --git a/content/projects/c-stuff.md b/content/projects/c-stuff.md
new file mode 100644
index 0000000..b310844
--- /dev/null
+++ b/content/projects/c-stuff.md
@@ -0,0 +1,22 @@
+$name c-stuff
+$source https://github.com/EliteTK/c-stuff
+
+c-stuff is a large collection of small projects and snippets of
+code. Numerous people have shown interest in these various snippets so
+although this is not a project itself, it gets a notable mention. Most
+of the code is licensed under the GNU GPLv3.
+
+$desc
+
+## Notable Mentions
+
+### timer
+
+timer is a simple command line beeping countdown timer. It has a very
+simple interface: `timer n{s,m,h,D,M,Y}...` Despite this simplicity,
+it's an incredibly useful tool, the source for it can be found
+[here][timer-src] and there is even an AUR package which can be found
+[here][timer-aur].
+
+[timer-src]: https://github.com/EliteTK/c-stuff/blob/master/timer.c "c-stuff/timer at master · EliteTK/c-stuff"
+[timer-aur]: https://aur.archlinux.org/packages/timer-git/ "timer-git"
diff --git a/content/projects/dotfiles.md b/content/projects/dotfiles.md
new file mode 100644
index 0000000..8c239e3
--- /dev/null
+++ b/content/projects/dotfiles.md
@@ -0,0 +1,6 @@
+$name dotfiles
+$source http://github.com/EliteTK/dotfiles/
+
+These are the files from my .config directory, the only things which are
+actually useful may be the vimrc, i3 config and i3blocks config. These are
+severely out of date.
diff --git a/content/projects/minecurses.md b/content/projects/minecurses.md
new file mode 100644
index 0000000..855ed59
--- /dev/null
+++ b/content/projects/minecurses.md
@@ -0,0 +1,8 @@
+$name minecurses
+$source https://github.com/EliteTK/minecurses/
+$aur minecurses-git
+
+minecurses is a clone of minesweeper written in C using ncurses. The
+code is quite awful in the current master branch and the redo branch is
+not in any way able to be compiled. However, in the future this might
+possibly improve.
diff --git a/content/projects/the-tk.com.md b/content/projects/the-tk.com.md
new file mode 100644
index 0000000..dc87f43
--- /dev/null
+++ b/content/projects/the-tk.com.md
@@ -0,0 +1,45 @@
+$name the-tk.com
+$source https://the-tk.com/cgit/the-tk.com/
+
+This website is an ongoing project of mine, an attempt at writing a simple to
+maintain static website with html which tries to avoid putting 
s +everywhere. I also hope that at least some of the stuff I write about can be +useful to some people. + +$desc + +## Older Versions + +The website is actually on its 4th revision. The files for the 1st revision may +be lost somewhere (probably for the best) but can find the source for v2 and v3 +of the website in the GitHub repository located [here][old-gh], the "old" branch +holds v2. v3 of the website relies on a slightly customized liquid, the nature +of this customization can be found [here][liquid-patch]. + +## IP Echo Server + +An IP echo server is hosted at http://ip.the-tk.com/. Before I was informed that +you could implement this functionality entirely within nginx (using +`return 200 $remote_addr`) I had written this short simple fastcgi IP echo +program in C: + +~~~.c +#include +#include +#include + +int main(void) +{ + while (FCGI_Accept() >= 0) { + puts("Content-type: text/plain; charset=UTF-8"); + puts("Status: 200 OK"); + puts(""); + printf("%s", getenv("REMOTE_ADDR")); + } + + return EXIT_SUCCESS; +} +~~~ + +[old-gh]: https://github.com/EliteTK/the-tk.com/ "EliteTK/the-tk.com · GitHub" +[liquid-patch]: https://github.com/EliteTK/liquid/tree/replace_newlines "EliteTK/liquid at replace_newlines" diff --git a/content/projects/vav.md b/content/projects/vav.md new file mode 100644 index 0000000..786c6cd --- /dev/null +++ b/content/projects/vav.md @@ -0,0 +1,6 @@ +$name VAV +$source https://github.com/EliteTK/vav/ + +VAV is a C library which aims to provide neat looking vectors in C. These might +not be entirely practical since they cause quite an overhead in the creation and +calculations using vectors, but the code can be a source of interesting ideas. diff --git a/content/style.scss b/content/style.scss new file mode 100644 index 0000000..e1873b8 --- /dev/null +++ b/content/style.scss @@ -0,0 +1,153 @@ +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%; + min-width: 60%; + 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 new file mode 100755 index 0000000..3c7f1f3 --- /dev/null +++ b/generate.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 + +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 markdown import markdown +from operator import attrgetter +from subprocess import call as run +from sys import argv +import meta +import os + +CONTENT = './content' +OUTPUT = './output' +KWORDS = { 'Tomasz Kramkowski', 'the-tk', 'blog', 'projects', 'TK', 'Arch-TK' } +ERRORS = { + 403: "Forbidden", + 404: "File Not Found", + 500: "Internal Server Error", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", +} + +md = lambda s: Markup(markdown(s, extensions=['markdown.extensions.fenced_code', + 'markdown.extensions.codehilite'])) + +File = namedtuple('File', 'content date slug ext') +def parse(path, has_date=False): + with open(path) as f: + content = meta.parse(f.read()) + slug, ext = os.path.splitext(os.path.split(path)[1]) + if has_date: + y, m, d, slug = slug.split('-', 3) + dat = date(int(y), int(m), int(d)) + else: + dat = None + return File(content, dat, slug, ext) + +Post = namedtuple('Post', 'title date tags pre content location') +def readpost(path): + pf = parse(path, has_date=True) + location = os.path.join('post', + '{:04}'.format(pf.date.year), + '{:02}'.format(pf.date.month), + '{:02}'.format(pf.date.day), + pf.slug + '.html') + tags = set(pf.content.meta.get('tags', [])) + return Post(' '.join(pf.content.meta['title']), pf.date, tags, + pf.content.sects['pre'], + '\n'.join(pf.content.sects.values()), location) + +Project = namedtuple('Project', 'name description source ml aur content location') +def readproject(path): + pf = parse(path) + source = pf.content.meta.get('source', [None])[0] + ml = pf.content.meta.get('ml', [None])[0] + aur = pf.content.meta.get('aur', [None])[0] + content = '\n'.join(pf.content.sects.values()) + location = os.path.join('project', pf.slug + '.html') + return Project(' '.join(pf.content.meta['name']), + pf.content.sects.get('desc', content), source, ml, aur, content, + location); + +def output(dest, cont): + dest = os.path.join(OUTPUT, dest) + destdir = os.path.dirname(dest) + if not os.path.exists(destdir): + os.makedirs(destdir) + with open(dest, 'w') as f: + f.write(cont) + +def outputpost(env, post, tags): + page = { + 'title': post.title, + 'description': md(post.pre), + 'keywords': ', '.join(KWORDS | post.tags), + 'date': post.date, + 'content': md(post.content), + 'tags': sorted(post.tags & set(tags)), + } + output(post.location, env.get_template('post.html').render(page=page)) + +def outputtag(env, posts, tag): + page = { + 'title': 'Posts tagged - {}'.format(tag), + 'description': "List of posts tagged '{}'.".format(tag), + 'keywords': ', '.join(KWORDS | {tag}), + 'tag': tag, + 'posts': [ p for p in posts if tag in p.tags ], + } + output('tag/{}.html'.format(tag), env.get_template('tag.html').render(page=page)) + +def outputproject(env, project): + page = { + 'title': project.name, + 'description': project.description.replace('\n', ' '), + 'keywords': ', '.join(KWORDS | {project.name}), + 'content': md(project.content), + 'source': project.source, + 'ml': project.ml, + 'aur': project.aur, + } + output(project.location, env.get_template('project.html').render(page=page)) + +def main(argv=['generate.py']): + from getopt import getopt + global OUTPUT + + opts = dict(getopt(argv[1:], "o:b:")[0]) + OUTPUT = opts.get('-o', OUTPUT) + baseurl = opts.get('-b', 'https://the-tk.com') + + run(['rm', '-rf', os.path.join(OUTPUT, '*')]) + + env = Environment(loader=FileSystemLoader('./templates'), autoescape=True) + env.globals['site'] = {'baseurl': baseurl} + env.filters['datefmt'] = lambda d, f='%Y-%m-%d': d.strftime(f) + + posts = glob(os.path.join(CONTENT, 'posts', '*')) + posts = [p for p in posts if not os.path.split(p)[1].startswith('_')] + posts = sorted(map(readpost, posts), key=attrgetter('date'), reverse=True) + tags = Counter(chain(*(p.tags for p in posts))) + tags = sorted(k for k, v in tags.items() if v > 1) + + page = { + 'title': 'Blog', + 'description': 'New posts will appear chronologically on this page.', + 'keywords': ', '.join(KWORDS), + 'tags': tags, + 'posts': posts, + } + output('blog.html', env.get_template('blog.html').render(page=page)) + + projects = glob(os.path.join(CONTENT, 'projects', '*')) + projects = [p for p in projects if not os.path.split(p)[1].startswith('_')] + projects = sorted(map(readproject, projects), key=lambda e: e.name.lower()) + + page = { + 'title': 'Projects', + 'description': 'This is a listing of all of my notable projects.', + 'keywords': ', '.join(KWORDS), + 'projects': projects, + } + output('projects.html', env.get_template('projects.html').render(page=page)) + + page = { + 'title': 'the-tk.com', + 'description': 'This is my website. Here you can find some blog posts and descriptions for notable projects.', + 'keywords': ', '.join(KWORDS), + 'posts': posts[:3], + } + output('index.html', env.get_template('index.html').render(page=page)) + + for post in posts: + outputpost(env, post, tags) + for tag in tags: + outputtag(env, posts, tag) + for project in projects: + outputproject(env, project) + + for code, error in ERRORS.items(): + page = { + 'title': 'Error: {} - {}'.format(code, error), + 'code': code, + 'error': error, + } + 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')]) + run(['cp', '-r', os.path.join(CONTENT, 'images'), OUTPUT]) + +if __name__ == '__main__': + from sys import argv + main(argv) diff --git a/meta.py b/meta.py new file mode 100644 index 0000000..7bb948d --- /dev/null +++ b/meta.py @@ -0,0 +1,28 @@ +from collections import OrderedDict, deque, namedtuple +import shlex + +Meta = namedtuple('Meta', ['sects', 'meta']) + +def _merge(l): + return ''.join(l).strip() +def _next(l): + sect = deque() + while l and not l[0].strip().startswith('$'): + sect.append(l.popleft()) + if not l: + return (('TRAIL', _merge(sect)), l) + name = l.popleft().strip()[1:] + sect = _merge(sect) + return ((name, sect), l) +def parse(s): + l = deque(s.splitlines(True)) + meta = dict() + sects = OrderedDict() + while l and l[0].strip().startswith('$'): + s = shlex.split(l[0][1:]) + meta[s[0]] = s[1:] + l.popleft() + while l: + s, l = _next(l) + sects[s[0]] = s[1] + return Meta(sects, meta) diff --git a/mksite.sh b/mksite.sh new file mode 100755 index 0000000..24aa43e --- /dev/null +++ b/mksite.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +./generate.py +tar -caf site.tgz -C output . +scp site.tgz erebus.the-tk.com: +ssh -t erebus.the-tk.com webtools/updateweb.sh diff --git a/output/.gitignore b/output/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/serve.sh b/serve.sh new file mode 100755 index 0000000..95e578b --- /dev/null +++ b/serve.sh @@ -0,0 +1,4 @@ +#!/bin/sh +./generate.py -o /tmp/servepages -b "http://0.0.0.0:8000" +cd /tmp/servepages || exit 1 +python -m http.server diff --git a/templates/blog.html b/templates/blog.html new file mode 100644 index 0000000..658f69d --- /dev/null +++ b/templates/blog.html @@ -0,0 +1,7 @@ +{% extends "default.html" %} +{% block content %} +

Posts

+
    {% for post in page.posts %} +
  • | {{ post.title }}{% endfor %} +
+{% endblock %} diff --git a/templates/default.html b/templates/default.html new file mode 100644 index 0000000..337cb20 --- /dev/null +++ b/templates/default.html @@ -0,0 +1,46 @@ + + + + {% block head %} + {{ page.title }} + + + + + + + + + {% endblock %} + + +
+
+ +
+
+ {% block content %}{% endblock %} +
+ +
+ + + diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..23ba358 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,5 @@ +{% extends "default.html" %} +{% block content %} +

Error

+

{{ page.code }} - {{ page.error }}

+{% endblock %} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..c32a7fb --- /dev/null +++ b/templates/index.html @@ -0,0 +1,22 @@ +{% extends "default.html" %} +{% block content %} +

Welcome

+ +

Welcome, this is my website, an under-maintained infodump. Hopefully you'll find something useful here.

+ +

Recent blogposts:

+
    {% for post in page.posts %} +
  • +
    +
    +

    {{ post.title }}

    +
    + {{ post.pre }} + Read more... +
    + +
    +
    +
  • +{% endfor %}
+{% endblock %} diff --git a/templates/post.html b/templates/post.html new file mode 100644 index 0000000..6cb47c3 --- /dev/null +++ b/templates/post.html @@ -0,0 +1,16 @@ +{% extends "default.html" %} +{% block content %} +
+
+

{{ page.title }}

+
+ {{ page.content }} +
{% if page.tags %} +
    +
  • Tags:
  • {% for tag in page.tags %} +
  • {{ tag }}
  • {% endfor %} +
{% endif %} + +
+
+{% endblock %} diff --git a/templates/project.html b/templates/project.html new file mode 100644 index 0000000..15e4d9a --- /dev/null +++ b/templates/project.html @@ -0,0 +1,16 @@ +{% extends "default.html" %} +{% block content %} +

{{ page.title }}

+{{ page.content }} +{% if page.source or page.ml %}
+
+{% if page.source %}
Source
+
{{ page.source }}
{% endif %} +{% if page.ml %}
Mailing list
+
{{ page.ml }}@the-tk.com + (archive)
{% endif %} +{% if page.aur %}
AUR
+
{{ page.aur }}
{% endif %} +
+{% endif %} +{% endblock %} diff --git a/templates/projects.html b/templates/projects.html new file mode 100644 index 0000000..7405542 --- /dev/null +++ b/templates/projects.html @@ -0,0 +1,11 @@ +{% extends "default.html" %} +{% block content %} +

Projects

+
    {% for project in page.projects %} +
  • +

    {{ project.name }}

    +

    {{ project.description }}

    + More info... +
  • {% endfor %} +
+{% endblock %} diff --git a/templates/tag.html b/templates/tag.html new file mode 100644 index 0000000..47c5fa0 --- /dev/null +++ b/templates/tag.html @@ -0,0 +1,7 @@ +{% extends "default.html" %} +{% block content %} +

Posts tagged - {{ page.tag }}

+
    {% for post in page.posts %} +
  • | {{ post.title }}{% endfor %} +
+{% endblock %} -- cgit v1.2.3-54-g00ecf