diff --git a/assets/css/style.css b/assets/css/style.css index aa3cb09..1223b9d 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -1,5 +1,14 @@ +@font-face { + font-family: "Ubuntu Medium"; + src: url(/ttf/ubuntu-medium.ttf) format("truetype"); +} + * { - font-family: "monospace"; + font-family: "Ubuntu Medium"; +} + +ul { + padding: 0 0 0 1rem; } code { @@ -7,3 +16,45 @@ code { background: #ACACAC; padding: 0.1rem; } + +#table-of-contents { + position: sticky; + top: 0; +} + +#content :is(h1, h2, h3, h4, h5, h6) { + display: inline; + border-bottom: 0.15rem solid #165578; + width: 100%; + padding-bottom: 0.1rem; + line-height: 1.75em; +} + +#organizer { + display: flex; + flex-direction: column; +} + +#content p { + flex-basis: auto; + text-align: justify; + text-justify: inter-word; +} + +.sidebar { + flex-basis: auto; +} + +@media only screen and (min-width: 768px) { + #organizer { + flex-direction: row; + } + + #content { + flex-basis: 80%; + } + + .sidebar { + flex-basis: 10%; + } +} diff --git a/assets/ttf/ubuntu-medium.ttf b/assets/ttf/ubuntu-medium.ttf new file mode 100644 index 0000000..5296045 Binary files /dev/null and b/assets/ttf/ubuntu-medium.ttf differ diff --git a/blog/emacs-the-journey-to-an-operating-system.org b/blog/emacs-the-journey-to-an-operating-system.org index f6f5242..7b89d43 100644 --- a/blog/emacs-the-journey-to-an-operating-system.org +++ b/blog/emacs-the-journey-to-an-operating-system.org @@ -1,34 +1,33 @@ #+TITLE: Emacs, the Journey to an Operating System -* Emacs, the Journey to an Operating System -** The Age without Emacs - It's the 12th of February, I'm playing Factorio on my laptop, when the bell rings and not long - after my Biology teacher enters the classroom, I quickly save and exit out of Factorio. After the - usual formalities I sit down and open my editor, so that I can take notes during the lesson. As - you might have guessed, I didn't open Emacs, instead I opened VSCode, yes I know, not even - VSCodium, but the prorietary spyware-filled version. I then open a new Markdown file and started - typing away. This procedure repeated multiple times during the day, until school ended and I got - home, I sat down in front of my desktop and opened CLion, because I wanted to do some coding in - Rust. I had VSCode opened on my desktop too, as I needed access to my notes, when one of my - classmates wanted them. I had two completely different editors opened almost all the time and - even vim, when I logged into remote servers and got to editing some =Dockerfile=. \\ - \\ - That is roughly how my day went, before I switched full time to Emacs and learned of all the - features the Emacs operating system has. I didn't even realize, how much I was missing out on - and how painful my existence was. Let's go over the different pain points I now, in retrospect, - realize existed. +* The Age without Emacs + It's the 12th of February, I'm playing Factorio on my laptop, when the bell rings and not long + after my Biology teacher enters the classroom, I quickly save and exit out of Factorio. After the + usual formalities I sit down and open my editor, so that I can take notes during the lesson. As + you might have guessed, I didn't open Emacs, instead I opened VSCode, yes I know, not even + VSCodium, but the prorietary spyware-filled version. I then open a new Markdown file and started + typing away. This procedure repeated multiple times during the day, until school ended and I got + home, I sat down in front of my desktop and opened CLion, because I wanted to do some coding in + Rust. I had VSCode opened on my desktop too, as I needed access to my notes, when one of my + classmates wanted them. I had two completely different editors opened almost all the time and + even vim, when I logged into remote servers and got to editing some =Dockerfile=. \\ + \\ + That is roughly how my day went, before I switched full time to Emacs and learned of all the + features the Emacs operating system has. I didn't even realize, how much I was missing out on + and how painful my existence was. Let's go over the different pain points I now, in retrospect, + realize existed. -*** The Pain - If you're an Emacs veteran, you surely have already noticed everything I'll point out in the - next few paragraphs, but please do read on as I present my unique view on the issues. +** The Pain + If you're an Emacs veteran, you surely have already noticed everything I'll point out in the + next few paragraphs, but please do read on as I present my unique view on the issues. -**** Multiple Editors - Let's start with the most obvious one, during "A day in the Life of Me", I would switch between - 3 different editors, being, in increasing order of time spent in each, VSCode, CLion and Vim. - This brings with it many issues, including but not limited to: keybindings, plugins/addons, - look&feel, features and even supported files/projects. The editors could be split into two - categories, classic: "CLion, VSCode" and "Vim". If you've spend even a minute on a *nix system, - you must know what Vim is and that, let's be honest, it has a weird, alien control scheme. This - "Weirdness" is even supported by a multitude of memes, such as: +*** Multiple Editors + Let's start with the most obvious one, during "A day in the Life of Me", I would switch between + 3 different editors, being, in increasing order of time spent in each, VSCode, CLion and Vim. + This brings with it many issues, including but not limited to: keybindings, plugins/addons, + look&feel, features and even supported files/projects. The editors could be split into two + categories, classic: "CLion, VSCode" and "Vim". If you've spend even a minute on a *nix system, + you must know what Vim is and that, let's be honest, it has a weird, alien control scheme. This + "Weirdness" is even supported by a multitude of memes, such as: diff --git a/blog/on-databases-docker-and-nix.org b/blog/on-databases-docker-and-nix.org new file mode 100644 index 0000000..879288d --- /dev/null +++ b/blog/on-databases-docker-and-nix.org @@ -0,0 +1,79 @@ +#+TITLE: On Docker Databases and Nixos + While learning Hashicorp Nomad+Vault+Consul, I decided that I'd convert all the Docker containers I use currently, + into their Nix-ified forms. In other words, I'd rewrite the ones I had, but I'd based them on NixOS, a truly + declarative enviroment, unlike /ehm/ all the other base images... Well, I didn't realize how *hard* it is to + "dockerize" databases, databases are inherently programs, which deal almost exclusively with state, as opposed to Nix + and Docker, which are both declarative systems (one of them is trying and failing really hard). + +** Configuration + Configuration is a rather big part of what systems administrator(DevOps engineer for the cool kids) does, one must + correctly configure a program, most of the time dynamically. And because this is such an important thing, it baffles + me, why 90% of all containers primarily use and support environment variables. I get that it's a convenient way to do + it, it's simple widely supported, uniform, all around great, but *really* cumbersome. Say your config file looks like + this: + + #+BEGIN_SRC conf + # stripped down Gitea configuration, I kept the parts that nicely illustrate my point + [server] + APP_DATA_PATH = /data/gitea + ROOT_URL = https://gitea.redalder.org/ + DOMAIN = gitea.redalder.org + + [database] + DB_TYPE = postgres + HOST = database-postgres + NAME = gitea + #+END_SRC + + The config has two sections, =server= and =database=, each of these sections has =n= key-value pairs. This has + structure, it has multiple layers and configuration files can get much, much more complex than that. Now, for the + sake of argument, let's imagine that we want to "environment-ize" this config. The natural, and frankly only way to + do this is to essentially flatten the config file, so we'd get something like this: + + #+BEGIN_SRC conf + SERVER_APP_DATA_PATH="/data/gitea" + SERVER_ROOT_URL="https://gitea.redalder.org/" + SERVER_DOMAIN="gitea.redalder.org" + + DATABASE_DB_TYPE="postgres" + DATABASE_HOST="database-postgres" + DATABASE_NAME="gitea" + #+END_SRC + + Now, you might think that this is completely fine, even reasonable, but let me explain to you why that is horrible. + First of, there is no imposed structure and structure is always good, nothing is preventing you from mixing the + =server= and =database= sections and while a "good" admin should not do that, it's best if they don't even have the + ability. Next depending on the parser, which parses this "configuration", you might encounter issues when you leave + out =""=, some are better at this than others, but once again, it's an implicit rule, which is bad. I hope you're + starting to understand the bigger picture, implicitness is *bad*, period. It introduces unnecessary mistakes that + could have been avoided if just the computer yelled at you. So why not give it the option to do that? + +** Configuration and Databases + Now, it's finally time to combine databases with configuration. What we get is an all out war between immutable, + declarative environments holding stateful and infinitely changing data. You must make sure that your configuration + gets applied only at first start, so you must keep state yourself! In a Docker container! Madness! Then comes the + joy of updating the configuration. Say you give your user the option to specify the default authentication method + ([[https://hub.docker.com/_/postgres][PostgreSQL]]), the user specifies that they want =scram-sha-256=, that's nice and all, so you apply it, but *only* on + the first boot. Why? Because now that the value is in the config file, if the user changed it, you'd have to figure + out *if* they changed it and then update the configuration file and that's really hard. The user might have gone into + where they store the state for PostgreSQL and manually changed the config file, they might have even completely + deleted your configuration and replaced it with their own? What should you do? Most Docker containers just take the + easy way out and do as PostgreSQL does and I don't blame them, there is nothing really that you can do. + +** Nix - The Solution? + Similar to some good literature, this rant has gone full circle. We're back at the start, back on the topic of + Nix. How can Nix save us? By removing unnecessary state. The mutable configuration file? Gone, it's immutable + now. Not knowing whether a setting changed? Poof, gone too, Nix is fully declarative, which means it identifies + *everything* by a sha256 hash in addition to its developer configured name. Nix also serves as a single point of + truth, which means even if the user modifies the config files, they will be overwritten before they are used + again. This makes mix ups are impossible. Messy and flat "configuration" files? Solved too, the Nix expression language can be + as flat or as deep as you need it to be, you can create complex APIs with functions and all that jazz. Basically Nix + is awesome! + +** Conclusion + The take-away from this rant, is that the best course of action is to figure out either how to completely replace + Docker and all the other container runtimes with something based on Nix, but since I'm a realist, I propose another + possible solution. We must get Nix to nicely work with Docker, so instead of clumsy environment variables, you'd + write your configuration in the form of Nix expressions and build a new docker image based on one common base. This + ensure that all configuration would be properly hashed and declarative, while allowing for much more complex config + files than environment variables or even templates. diff --git a/make.el b/make.el index a8dddd9..e846e61 100644 --- a/make.el +++ b/make.el @@ -5,11 +5,101 @@ ;;; Code: (load-file "./org-thtml/ox-thtml.el") (require 'org) +(require 'ox) +(require 'ox-html) (dolist (d '("public_html")) (unless (file-exists-p d) (make-directory d))) +;; https://alhassy.github.io/AlBasmala.html#Floating-TOC +(advice-add 'org-html--translate :before-until 'display-toc-as-toc) +(defun display-toc-as-toc (phrase info) + (when (equal phrase "Table of Contents") + " + TOC + ")) + +;; https://github.com/alphapapa/unpackaged.el#export-to-html-with-useful-anchors +(advice-add #'org-export-get-reference :override #'unpackaged/org-export-get-reference) + +(defun unpackaged/org-export-get-reference (datum info) + "Like `org-export-get-reference', except uses heading titles instead of random numbers." + (let ((cache (plist-get info :internal-references))) + (or (car (rassq datum cache)) + (let* ((crossrefs (plist-get info :crossrefs)) + (cells (org-export-search-cells datum)) + ;; Preserve any pre-existing association between + ;; a search cell and a reference, i.e., when some + ;; previously published document referenced a location + ;; within current file (see + ;; `org-publish-resolve-external-link'). + ;; + ;; However, there is no guarantee that search cells are + ;; unique, e.g., there might be duplicate custom ID or + ;; two headings with the same title in the file. + ;; + ;; As a consequence, before re-using any reference to + ;; an element or object, we check that it doesn't refer + ;; to a previous element or object. + (new (or (cl-some + (lambda (cell) + (let ((stored (cdr (assoc cell crossrefs)))) + (when stored + (let ((old (org-export-format-reference stored))) + (and (not (assoc old cache)) stored))))) + cells) + (when (org-element-property :raw-value datum) + ;; Heading with a title + (unpackaged/org-export-new-title-reference datum cache)) + ;; NOTE: This probably breaks some Org Export + ;; feature, but if it does what I need, fine. + (org-export-format-reference + (org-export-new-reference cache)))) + (reference-string new)) + ;; Cache contains both data already associated to + ;; a reference and in-use internal references, so as to make + ;; unique references. + (dolist (cell cells) (push (cons cell new) cache)) + ;; Retain a direct association between reference string and + ;; DATUM since (1) not every object or element can be given + ;; a search cell (2) it permits quick lookup. + (push (cons reference-string datum) cache) + (plist-put info :internal-references cache) + reference-string)))) + +(defun unpackaged/org-export-new-title-reference (datum cache) + "Return new reference for DATUM that is unique in CACHE." + (cl-macrolet ((inc-suffixf (place) + `(progn + (string-match (rx bos + (minimal-match (group (1+ anything))) + (optional "--" (group (1+ digit))) + eos) + ,place) + ;; HACK: `s1' instead of a gensym. + (-let* (((s1 suffix) (list (match-string 1 ,place) + (match-string 2 ,place))) + (suffix (if suffix + (string-to-number suffix) + 0))) + (setf ,place (format "%s--%s" s1 (cl-incf suffix))))))) + (let* ((title (org-element-property :raw-value datum)) + (ref (url-hexify-string (substring-no-properties title))) + (parent (org-element-property :parent datum))) + (while (--any (equal ref (car it)) + cache) + ;; Title not unique: make it so. + (if parent + ;; Append ancestor title. + (setf title (concat (org-element-property :raw-value parent) + "--" title) + ref (url-hexify-string (substring-no-properties title)) + parent (org-element-property :parent parent)) + ;; No more ancestors: add and increment a number. + (inc-suffixf ref))) + ref))) + (defvar org-publish-project-alist) (setq org-publish-project-alist `(("blog-org" @@ -28,7 +118,7 @@ :base-directory ,(expand-file-name "assets/") :publishing-directory ,(expand-file-name "public_html/") :recursive t - :base-extension "\\(jpg\\|gif\\|png\\|css\\|js\\|el\\|nb\\|ipynb\\|pdf\\|xml\\)" + :base-extension "\\(ttf\\|jpg\\|gif\\|png\\|css\\|js\\|el\\|nb\\|ipynb\\|pdf\\|xml\\)" :publishing-function org-publish-attachment) ("blog" :components ("blog-org" "blog-assets")))) diff --git a/templates/blog.html b/templates/blog.html index b067f5e..f2f9819 100644 --- a/templates/blog.html +++ b/templates/blog.html @@ -2,17 +2,14 @@ {{:include "head.html"}} - -
-
- -
- {{:if with-title}}

{{title}}

{{:endif}} - {{:if date}}{{:endif}} - {{contents}} -
- +
+ +
+ {{:if with-title}}

{{title}}

{{:endif}} + {{:if date}}{{:endif}} + {{contents}}
+