Summary Files Commits Branches @commit @diff @stats
path: root / src / blog
diff options
context:
space:
mode:
Commit6b8cae12cb5d60b37931332d9d8008649ae14566 (patch)
Author
 Syndamia <kamen@syndamia.com>
2026-09-12 11:31:19 +0300
Committer
 Syndamia <kamen@syndamia.com>
2026-09-12 13:54:29 +0300
Files9ff20cdba71fff44e7b23b43e46a75276df6d7f1 /src/blog
syndamia.com-6b8cae12cb5d60b37931332d9d8008649ae14566.tar
syndamia.com-6b8cae12cb5d60b37931332d9d8008649ae14566.tar.gz
syndamia.com-6b8cae12cb5d60b37931332d9d8008649ae14566.zip
Parent918bac7614e560678d51bfba2a25582a3284bdd9 (diff)
feat!: Update dunbar markup
Currently the newest version of the markup is not on the main branch, mostly because of polish and the documentation. As an effect from the changes to the language, the sitemap is the only thing which needs to be created externally.
50 files changed, 2342 insertions, 1977 deletions
-rw-r--r--src/blog/2.6-years-of-web-design/index.du124
-rw-r--r--src/blog/bash-is-weird/index.du55
-rw-r--r--src/blog/connect-to-mysql-in-dotnet-ef/index.du58
-rw-r--r--src/blog/disable-sticky-keys-popup/index.du32
-rw-r--r--src/blog/encrypted-email/index.du116
-rw-r--r--src/blog/export-skype/index.du72
-rw-r--r--src/blog/fix-network-brother-printers/index.du44
-rw-r--r--src/blog/fix-no-frame-buffer-plan9/index.du35
-rw-r--r--src/blog/fix-qc-timeout/index.du30
-rw-r--r--src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du35
-rw-r--r--src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du202
-rw-r--r--src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du76
-rw-r--r--src/blog/gns3-initsh-no-such-file/index.du12
-rw-r--r--src/blog/how-to-encrypt-email/index.du163
-rw-r--r--src/blog/how-to-use-jira/bug.du25
-rw-r--r--src/blog/how-to-use-jira/cards.du147
-rw-r--r--src/blog/how-to-use-jira/components.du47
-rw-r--r--src/blog/how-to-use-jira/dashboards.du64
-rw-r--r--src/blog/how-to-use-jira/filters.du44
-rw-r--r--src/blog/how-to-use-jira/index.du87
-rw-r--r--src/blog/how-to-use-jira/kanban.du35
-rw-r--r--src/blog/how-to-use-jira/pages.du24
-rw-r--r--src/blog/how-to-use-jira/projects.du141
-rw-r--r--src/blog/how-to-use-jira/releases.du23
-rw-r--r--src/blog/how-to-use-jira/scrum.du53
-rw-r--r--src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.du74
-rw-r--r--src/blog/index.du137
-rw-r--r--src/blog/install-drivers-for-epson-scanners/index.du40
-rw-r--r--src/blog/install-plan9-with-virt-manager/index.du66
-rw-r--r--src/blog/making-sense-of-android-root/index.du69
-rw-r--r--src/blog/managing-apps-with-adb-without-root/index.du116
-rw-r--r--src/blog/microsoft-and-foss-extinguish/index.du48
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/basic-concepts.du34
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/index.du51
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/introduction.du51
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/timeline.du40
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/user-interface.du63
-rw-r--r--src/blog/plan9-in-linux-mouse-menus/index.du161
-rw-r--r--src/blog/remove-weather-widget/index.du18
-rw-r--r--src/blog/sane-explanation-of-compilers/index.du12
-rw-r--r--src/blog/sane-explanation-of-compilers/part-1/index.du633
-rw-r--r--src/blog/switchut-izgorq/index.du22
-rw-r--r--src/blog/taming-the-fun-too/index.du64
-rw-r--r--src/blog/the-physics-behind-a-black-hole-shader/index.du233
-rw-r--r--src/blog/thinkpad-x270-my-favorite-machine/index.du93
-rw-r--r--src/blog/thoughts-on-minecraft-design/index.du331
-rw-r--r--src/blog/turn-off-notifications-windows/index.du24
-rw-r--r--src/blog/virt-manager-freeze-on-browse/index.du18
-rw-r--r--src/blog/when-a-language-forces-simpler-thinking/index.du34
-rw-r--r--src/blog/windows-run-dialog/index.du143
diff --git a/src/blog/2.6-years-of-web-design/index.du b/src/blog/2.6-years-of-web-design/index.du
index 2678065..5b99ea7 100644
--- a/src/blog/2.6-years-of-web-design/index.du
+++ b/src/blog/2.6-years-of-web-design/index.du
@@ -1,23 +1,23 @@
-# 2.6 years of web design
+'def title 2.6 years of web design
+'def desc Outlining my experience with Web design while making this website
-'define expected-reading 13 min
-'define created 23 December 2022
-'define edited 23 December 2022
-[$pagenav]
+# {title}
+
+{pagenav 13 min;23 December 2022;23 December 2022}
:contents
.numbered
-1. [url #v1.0 v1.0]
-2. [url #v2.0 v2.0]
-3. [url #v2.1 v2.1]
-4. [url #v2.2 v2.2]
-5. [url #v3.0 v3.0]
-6. [url #v3.1 v3.1]
-7. [url #now now]
-8. [url #appendix Appendix]
+1. {uhref v1.0}
+2. {uhref v2.0}
+3. {uhref v2.1}
+4. {uhref v2.2}
+5. {uhref v3.0}
+6. {uhref v3.1}
+7. {uhref now}
+8. {uhref Appendix}
-On 17 May 2020 I [url https://gitlab.com/Syndamia/syndamiadotcom/-/commit/f2d3991cf3381d4d794b3faa2890439bb70af729 pushed the very first version of this website], which went live 3 days later.
+On 17 May 2020 I {url pushed the very first version of this website;https://gitlab.com/Syndamia/syndamiadotcom/-/commit/f2d3991cf3381d4d794b3faa2890439bb70af729}, which went live 3 days later.
The whole idea of making my own website came on a whim: I had recently turned 18 and spent some of my money on getting a small VPS (which was primarily used for cloud storage).
There was no plan and I had never done anything like it, so a shitty website was to be expected.
@@ -25,66 +25,66 @@ There was no plan and I had never done anything like it, so a shitty website was
Looking back at it now, that first design's color palette was comprised of three dull grey colors, which didn't contrast very much on the white font:
-[image ./img/v1.0-index.png]
+{img ./img/v1.0-index.png}
For code blocks, the background was a dark-blue color with a blue-ish font color, absolutely horrible for readability:
-[image ./img/v1.0-code\ block.png]
+{img block.png;./img/v1.0-code block.png}
-Although I wasn't the one to invent that color scheme, it was [*inspired*] from [url https://github.com/linuxmint/xed xed]'s Oblivion theme.
+Although I wasn't the one to invent that color scheme, it was {i inspired} from {url xed;https://github.com/linuxmint/xed}'s Oblivion theme.
It wasn't all completely bonkers, there were some not-so-ugly design decisions.
Navigation was done with tabs, which look decently nice on a desktop.
On blog posts, and especially on those with multiple pages, you would have the title on the left, and a close button on the right, "mimicking" a browser window.
-[image ./img/v1.0-tutorial-page.png]
+{img ./img/v1.0-tutorial-page.png}
As you can imagine, this was a scalability nightmare. If the title was too long or there were too many pages, stuff would overlap in an unreadable manner:
-[image ./img/v1.0-index-smallscreen.png]
+{img ./img/v1.0-index-smallscreen.png}
-You know, if this website was published on [url https://neocities.org/ neocities], my desktop-oriented unscaleable layout might've been seen as cool and novel...
+You know, if this website was published on {url neocities;https://neocities.org/}, my desktop-oriented unscaleable layout might've been seen as cool and novel...
Thankfully (or maybe unfortunately), I didn't go down that road.
Finally, tables, like those used in the "Projects" listing, were the absolute dumbest:
-[image ./img/v1.0-projects.png]
+{img ./img/v1.0-projects.png}
As you can see, the design was overwhelmingly ugly, with many boneheaded decisions behind it.
-Did I mention every post had to be written entirely by hand in HTML, except for the headers and footers, which were [url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/v1.0/website/js [=generated client-side with JavaScript=]]?
+Did I mention every post had to be written entirely by hand in HTML, except for the headers and footers, which were {url {b generated client-side with JavaScript};https://gitlab.com/Syndamia/syndamiadotcom/-/tree/v1.0/website/js}?
-Nonetheless, it served as a good starting point and stepping stone, for my web development [*adventures*].
+Nonetheless, it served as a good starting point and stepping stone, for my web development {i adventures}.
### v2.0
-Less than two months later, on 21 July, [url https://gitlab.com/Syndamia/syndamiadotcom/-/commit/64fbbd514733e42dd047bf65c511563a84ebd629 I did a complete redesign].
-To more easily separate the two, I decided to use [url https://gitlab.com/Syndamia/syndamiadotcom/-/releases releases], where a major version would signify a major styling change, and minor versions would be reserved for other important changes, like how the whole website is generated.
+Less than two months later, on 21 July, {url I did a complete redesign;https://gitlab.com/Syndamia/syndamiadotcom/-/commit/64fbbd514733e42dd047bf65c511563a84ebd629}.
+To more easily separate the two, I decided to use {url releases;https://gitlab.com/Syndamia/syndamiadotcom/-/releases}, where a major version would signify a major styling change, and minor versions would be reserved for other important changes, like how the whole website is generated.
Speaking of generated, I actually went away with the old "system" of manual labour, and turned to technology for aid.
-It's all thanks to [url https://www.youtube.com/@WolfgangsChannel Wolfgang's Channel]'s tutorial on making a [url https://www.youtube.com/watch?v=N_ttw2Dihn8 "Fast & Minimal Blog"].
-There, he showed how to setup and use [url https://www.romanzolotarev.com/ssg.html ssg] with [url https://kristaps.bsd.lv/lowdown/ lowdown], a combination that still powers this website.
+It's all thanks to {url Wolfgang's Channel;https://www.youtube.com/@WolfgangsChannel}'s tutorial on making a {url "Fast & Minimal Blog";https://www.youtube.com/watch?v=N_ttw2Dihn8}.
+There, he showed how to setup and use {url ssg;https://www.romanzolotarev.com/ssg.html} with {url lowdown;https://kristaps.bsd.lv/lowdown/}, a combination that still powers this website.
Turning to the actual website itself, now it looked quite pleasant, in the day at least:
-[image ./img/v2.0-index.png]
+{img ./img/v2.0-index.png}
Rather than using multiple colors for different elements, I went for a monochrome "printed on a piece of paper" look.
One might call that regression, but I'd like to think of it as minimalism.
Looking at those same code blocks and tables:
-[image ./img/v2.0-code\ block.png]
-[image ./img/v2.0-resume.png]
+{img block.png;./img/v2.0-code block.png}
+{img ./img/v2.0-resume.png}
Ay, that's pretty clean! But it should remind you of something.
Before, the only time I would work with Markdown files was in GitHub READMEs.
So, with that association in place, replicating GitHub's style was a natural choice.
-Though that last part wasn't done by me, but by [url https://github.com/sindresorhus/github-markdown-css sindresorhus].
+Though that last part wasn't done by me, but by {url sindresorhus;https://github.com/sindresorhus/github-markdown-css}.
As for the overall design, there isn't too much to say.
Yes, the original tab idea kinda lived on, as those buttons at the top, and yes, it still wasn't scaleable, but now it didn't even try to be.
-[image ./img/v2.0-index-smartphone.png]
+{img ./img/v2.0-index-smartphone.png}
Overall, this made it more "commercialized", soulless (assuming v1.0 had one) and plain old boring.
It seems I hit the other end of the spectrum, from ugly but interesting to pleasing but dull.
@@ -93,7 +93,7 @@ It seems I hit the other end of the spectrum, from ugly but interesting to pleas
Over the following half a year, I wrote a couple more articles, but most importantly the styling was finally made scaleable:
-[image ./img/v2.1-index-smartphone.png]
+{img ./img/v2.1-index-smartphone.png}
Ignoring my big fat head taking up 70% of the screen, the index page properly fit on a mobile screen!
The navigation tabs weren't very symmetrically organized, but at least nothing was overlapping and overflowing over the screen.
@@ -101,9 +101,9 @@ The navigation tabs weren't very symmetrically organized, but at least nothing w
### v2.2
Still, by that time I started to get criminally bored by that black and white appearance.
-As an avid fan of not hurting my eyes and [url https://github.com/morhetz/gruvbox gruvbox], a color overhaul needed to be done.
+As an avid fan of not hurting my eyes and {url gruvbox;https://github.com/morhetz/gruvbox}, a color overhaul needed to be done.
-But I'm getting ahead of myself, we need to sidetrack to a project I was working on at the time of [url https://gitlab.com/Syndamia/syndamiadotcom/-/releases/v2.1 2.1's release]: [url https://github.com/Team-Kaleidoscope DevHive].
+But I'm getting ahead of myself, we need to sidetrack to a project I was working on at the time of {url 2.1's release;https://gitlab.com/Syndamia/syndamiadotcom/-/releases/v2.1}: {url DevHive;https://github.com/Team-Kaleidoscope}.
Sparing you the details, it was a social media app, with detached front-end and back-end.
Me and two other guys worked on it for about 5 months, from December 2020 to April 2021, as a course project.
@@ -111,23 +111,23 @@ Up until this point, the course I'm talking about almost didn't touch front-end
As you might imagine, I was the only one with any idea of web design, meaning I was the "lead designer".
This time, however, I wanted to do it a bit more properly, so I made mockups of the final design.
-The first was done in [url https://pencil.evolus.vn/ Pencil], a somewhat limited application for designing layouts:
+The first was done in {url Pencil;https://pencil.evolus.vn/}, a somewhat limited application for designing layouts:
-[image ./img/devhive-index-concept1.png]
+{img ./img/devhive-index-concept1.png}
Pretty quickly I turned to actual HTML and CSS, because I needed a more realistic feel of how the actual elements would be laid out.
Another idea that came up to mind was using a palette: a certain selection of colors for everything.
After talking with the others, I found a decent selection of blue and orange sunset-y colours and got to work.
The end result was this beauty:
-[image ./img/devhive-index-concept2.png]
+{img ./img/devhive-index-concept2.png}
Although it looked pretty nice, we decided against it, since the focus was on the back-end, the front-end needed to be simpler.
There are also some problems with the color scheme, but more on that later.
Then I did what I had already done before: simplified the devil out of it.
-[image ./img/devhive-index-concept3.png]
+{img ./img/devhive-index-concept3.png}
Now this looks way too cartoon-ish, you could make it with a steady hand and a ruler on a sheet of paper.
However it made the others happy, so we went along with it.
@@ -135,7 +135,7 @@ However it made the others happy, so we went along with it.
The overall flatness and emptiness, and general boringness bugged me for a while.
Some time later, after messing around for a couple hours, I came up with this:
-[image ./img/devhive-index-concept4.png]
+{img ./img/devhive-index-concept4.png}
A much more modern-looking and feeling concept, completely different from it's comic roots.
Unfortunately, we didn't go with it, later we found out it had some issues with certain elements, and the previous idea was already implemented.
@@ -156,14 +156,14 @@ I needed something in between the second and third concepts, something which was
Coincidentally, at the same time, I was working on a dark colored implementation of my website, using the gruvbox color.
Putting two and two together, I came up with this thing;
-[image ./img/devhive-index-concept5.png]
+{img ./img/devhive-index-concept5.png}
Now this looked really nice, somewhat professional even, was very simple and didn't hurt your eyes.
Suffice to say, everyone loved it, and we redid everything to look like it.
As for my own website, this is what it looked like by the time I made release 2.2:
-[image ./img/v2.2-index.png]
+{img ./img/v2.2-index.png}
There is no point in showing code blocks or other elements, since it was just a change of colors.
But boy oh boy how long it took to make such a simple change.
@@ -171,31 +171,31 @@ That's where everything stayed for a while.
### v3.0
-Of course, there were changes, I wrote more posts, tweaked some of the styling, hell, I even started adding ([=non required=]) JavaScript functionality.
+Of course, there were changes, I wrote more posts, tweaked some of the styling, hell, I even started adding ({b non required}) JavaScript functionality.
Still, I was yearning for something better.
Scalability was continuing to be an issue, outside of the annoying misalignment, navigation buttons in the header or footer would disappear into the void if it's contents were too long:
-[image ./img/v2.2-index-footer-smallwidth.png]
+{img ./img/v2.2-index-footer-smallwidth.png}
This example is unrealistic, but there were times where I wanted to put something longer in the footer button, and this issue arose.
Also the whole button idea wasn't very expandable, what if I wanted to have not 6 but more than 20 buttons in the header up top?
-[image ./img/v2.2-index-full-header.png]
+{img ./img/v2.2-index-full-header.png}
And don't get me started on how comically bad this is on mobile:
-[image ./img/v2.2-index-full-header-smartphone.png]
+{img ./img/v2.2-index-full-header-smartphone.png}
Something needed to change yet again, and something did.
-A year and a third later, on [url https://gitlab.com/Syndamia/syndamiadotcom/-/commit/bde3ebdea6310c891b7e38185906d1a1e03977e4 3 July 2022], I went away with the tabbed-like button layout, and opted for a dead simple sidebar:
+A year and a third later, on {url 3 July 2022;https://gitlab.com/Syndamia/syndamiadotcom/-/commit/bde3ebdea6310c891b7e38185906d1a1e03977e4}, I went away with the tabbed-like button layout, and opted for a dead simple sidebar:
-[image ./img/v3.0-index-initial.png]
+{img ./img/v3.0-index-initial.png}
About that useless right border and the weird choice for only left and bottom borders on the sidebar: I wanted some separation for the sidebar and I wanted more "fun" in the overall design.
-Most of the inspiration for those came from [url https://jvns.ca/ Julia Evan's blog], where there is a big orange ribbon running on the sides and across the page.
+Most of the inspiration for those came from {url Julia Evan's blog;https://jvns.ca/}, where there is a big orange ribbon running on the sides and across the page.
Over time I did more tweaking on the colors and layout of everything, so by the time I created release 3.0, it looked like this:
-[image ./img/v3.0-index.png]
+{img ./img/v3.0-index.png}
A good question you might be asking yourself is "How is this supposed to be scaleable?"
The answer is that it kinda of wasn't, at the time.
@@ -210,41 +210,41 @@ The whole point of DevHive's final redesign was to use colors for better separat
But that completely when over my head when I initially did that 3.0 redesign.
Fortunately, it later came back.
-It might've been four and a half months later, but I finally [url https://gitlab.com/Syndamia/syndamiadotcom/-/commit/55afc85bf7da9c0ed5e8859027080aebfa55ec50 added color separation between the background and article and navbar].
+It might've been four and a half months later, but I finally {url added color separation between the background and article and navbar;https://gitlab.com/Syndamia/syndamiadotcom/-/commit/55afc85bf7da9c0ed5e8859027080aebfa55ec50}.
-[image ./img/v3.1-index.png]
+{img ./img/v3.1-index.png}
And about that unfixed scalability?
Well, I fixed it, now on a mobile devices, the navbar stays up top, but is shrunk and can be expanded with a button:
-[image ./img/v3.1-index-smartphone.png]
+{img ./img/v3.1-index-smartphone.png}
Another notable styling change was in tables.
-I pretty much stole the design from [url https://www.lemmi.no/ LEMMiNO]'s website:
+I pretty much stole the design from {url LEMMiNO;https://www.lemmi.no/}'s website:
-[image ./img/v3.1-table.png]
+{img ./img/v3.1-table.png}
Finally, probably the most important change of it all, before I used some bash scripts to automate certain actions in the result HTML files, like generating the description automatically.
-Now, this was all done with [url https://www.gnu.org/software/gawk/manual/gawk.html awk], a programming language specifically designed for making text changes to files.
-awk's flexibility permitted me to create stuff like [url /talks/demo.html the slide presentation system] without too much trouble.
+Now, this was all done with {url awk;https://www.gnu.org/software/gawk/manual/gawk.html}, a programming language specifically designed for making text changes to files.
+awk's flexibility permitted me to create stuff like {url the slide presentation system;/talks/demo.html} without too much trouble.
### now
As of the writing of this post, not too much has changed since the last release.
-There have been new posts, like this one and [url /blog/taming-the-fun-too Taming the Fun-too] but the overall design is here to stay, at least until I learn more about creating web styles and/or get bored of the current one.
+There have been new posts, like this one and {url Taming the Fun-too;/blog/taming-the-fun-too} but the overall design is here to stay, at least until I learn more about creating web styles and/or get bored of the current one.
Happy holidays everyone!
### Appendix
This post has been in the works since 01 August 2020.
-At the time it was just called [url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/501942b638c34582de2f73dc31423c9322eb81fd/src/blog/syndamiadotcom "syndamiadotcom"] and was listed under the now defunct "Projects" section.
-It was actually still available on the website, under [`/blog/syndamiadotcom/`], but I didn't list it in the blogs page.
+At the time it was just called {url "syndamiadotcom";https://gitlab.com/Syndamia/syndamiadotcom/-/tree/501942b638c34582de2f73dc31423c9322eb81fd/src/blog/syndamiadotcom} and was listed under the now defunct "Projects" section.
+It was actually still available on the website, under {` /blog/syndamiadotcom/}, but I didn't list it in the blogs page.
That first iteration looked at the layout in a much stiffer and uninteresting way.
I was talking about what exact color codes I used for crying out loud.
But it was left as-is because I struggled on how to approach it.
-I'm still not entirely happy with this version either, [url #v2.2 v2.2] was probably the most interesting and valuable part of the whole thing and the rest was fairly meh.
+I'm still not entirely happy with this version either, {url v2.2;#v2.2} was probably the most interesting and valuable part of the whole thing and the rest was fairly meh.
Oh well, maybe I'll rewrite it again one day.
However, for the time being, I believe it's better for me to expect a bit less and just put stuff out there.
@@ -252,4 +252,4 @@ As you saw, learning the little I know about web design was a slow trial and err
The same will happen with making blog posts and other articles.
I'm not a writer and I'm not interested enough to learn things properly.
-[*P.S.*] Expect this post to be updated in the future, when I make new releases!
+{i P.S.} Expect this post to be updated in the future, when I make new releases!
diff --git a/src/blog/bash-is-weird/index.du b/src/blog/bash-is-weird/index.du
index 3fbc2cd..8fe78cf 100644
--- a/src/blog/bash-is-weird/index.du
+++ b/src/blog/bash-is-weird/index.du
@@ -1,30 +1,31 @@
-# BASH is weird
+'def title BASH is weird
+'def desc Interesting quirks of BASH
-'define expected-reading 4 min
-'define created 01 May 2023
-'define edited 02 May 2023
-[$pagenav]
+# {title}
-'footnote parameter-expansion Of course this is just one of the many ways to reference and work with variables.
-For very basic stuff, BASH is decently simple and intuitive, for example variables are set with the format [`name=value`] and they're referenced with [`\$name`] [$parameter-expansion].
-However, that changes once you start diving deeper (as I had to do for my [url /talks/linuxgraphy-by-strabo Linuxgraphy by Strabo] presentation).
+{pagenav 4 min;01 May 2023;02 May 2023}
+
+For very basic stuff, BASH is decently simple and intuitive, for example variables are set with the format {` name=value} and they're referenced with {` $name} {fn Of course this is just one of the many ways to reference and work with variables.}.
+However, that changes once you start diving deeper (as I had to do for my {url Linuxgraphy by Strabo;/talks/linuxgraphy-by-strabo} presentation).
An example which illustrates my point would be:
```bash
+'emplace
myvar=($(echo A B C))
myvar=1234
-echo $((myvar += 46)) ${myvar[\${myvar:0:1}]}
+echo $((myvar += 46)) ${myvar[${myvar:0:1}]}
+'endemplace
It has 3 things which really bothered me:
:ordered
-1. The output of [`\$(echo A B C)`] is replaced "literally", and then the whole expression is evaluated.
- Meaning, [`myvar=($(echo A B C))`] turns into [`myvar=(A B C)`], which creates an array with those three letters.
+1. The output of {` $(echo A B C)} is replaced "literally", and then the whole expression is evaluated.
+ Meaning, {` myvar=($(echo A B C))} turns into {` myvar=(A B C)}, which creates an array with those three letters.
.p
- I thought the "returned" value of [`\$(echo A B C)`] would be the whole string "A B C", so the array would have one element, that string.
- However, [`\$()`] isn't really a function, which takes arguments, "creates" commands and returns their output.
- It's [url https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html Command [=Substitution=]], the text gets executed and it's output [=replaces=] the [`\$(...)`] itself (slightly reminiscent of [url https://lispcookbook.github.io/cl-cookbook/macros.html LISP macros]).
+ I thought the "returned" value of {` $(echo A B C)} would be the whole string "A B C", so the array would have one element, that string.
+ However, {` $()} isn't really a function, which takes arguments, "creates" commands and returns their output.
+ It's {url Command {b Substitution};https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html}, the text gets executed and it's output {b replaces} the {` $(...)} itself (slightly reminiscent of {url LISP macros;https://lispcookbook.github.io/cl-cookbook/macros.html}).
.p
Side note: obviously, the original expected behaviour can happen if we use some quotes:
@@ -32,34 +33,36 @@ It has 3 things which really bothered me:
```bash
myvar=("$(echo A B C)")
-2. On the second line, [`myvar`] [*becomes*] an integer and then we do an arithmetic operation on it, nothing wrong here.
- [`\${parameter:offset:length}`] returns the substring from [`parameter`] from [`offset`] with size [`length`], but we're giving it a "number", so it should either throw some sort of error or return something default, like 0.
+2. On the second line, {` myvar} {i becomes} an integer and then we do an arithmetic operation on it, nothing wrong here.
+ {` $\{parameter:offset:length\}} returns the substring from {` parameter} from {` offset} with size {` length}, but we're giving it a "number", so it should either throw some sort of error or return something default, like 0.
However it correctly returns the number 1 (and no, that isn't a default, the number is correctly parsed as a string).
.p
This shows that numbers are actually strings too, and numerical operations are just weird string operations.
- Contrary to any dynamically-typed language, it's not like the type of a variable is inferred from it's value, [url https://tldp.org/LDP/abs/html/untyped.html there isn't a type at all]!
- Which makes everything even more weird, considering you [*can*] [url https://www.gnu.org/software/bash/manual/bash.html#index-declare create variables with a specific type].
+ Contrary to any dynamically-typed language, it's not like the type of a variable is inferred from it's value, {url there isn't a type at all;https://tldp.org/LDP/abs/html/untyped.html}!
+ Which makes everything even more weird, considering you {i can} {url create variables with a specific type;https://www.gnu.org/software/bash/manual/bash.html#index-declare}.
-3. Finally, the arguably biggest weirdness of it all, is [`\${myvar[1]}`].
- It doesn't matter how it is represented, at first [`myvar`] was the list of values A, B, C and now it's a number, this should return nothing.
- Per contra, the value [`B`] is returned instead!
+3. Finally, the arguably biggest weirdness of it all, is {` $\{myvar[1]\}}.
+ It doesn't matter how it is represented, at first {` myvar} was the list of values A, B, C and now it's a number, this should return nothing.
+ Per contra, the value {` B} is returned instead!
.p
- Via trial and error, we find that our number will be returned when the index is 0, and with index 2 we get [`C`].
+ Via trial and error, we find that our number will be returned when the index is 0, and with index 2 we get {` C}.
So all variables are arrays, and by default for integer and string operations, the first value is used?
.p
- This is strange, but it cannot be the full picture, because [url https://linux.die.net/Bash-Beginners-Guide/sect_10_01.html names have attributes], alongside it's type, a variable (name) can be read-only, but also have the "trace" flag, which only works with functions.
+ This is strange, but it cannot be the full picture, because {url names have attributes;https://linux.die.net/Bash-Beginners-Guide/sect_10_01.html}, alongside it's type, a variable (name) can be read-only, but also have the "trace" flag, which only works with functions.
So, variables and functions are the same "object"?
Unfortunately, I couldn't find any definitive information on the topic, so this train of thought will have to be left unresolved.
-And this is just one example, more bizarreness can be found with [url https://www.vidarholen.net/contents/blog/?p=25 square brackets] and [url https://mywiki.wooledge.org/BashPitfalls most ok looking code].
-[url https://chrisdone.com/posts/shell-conduit/ Some people] even go as far to say:
+And this is just one example, more bizarreness can be found with {url square brackets;https://www.vidarholen.net/contents/blog/?p=25} and {url most ok looking code;https://mywiki.wooledge.org/BashPitfalls}.
+{url Some people;https://chrisdone.com/posts/shell-conduit/} even go as far to say:
.quote
Its syntax is insane, incredibly error prone, its defaults are awful, and it’s not a real big person programming language.
-But I believe that is a step too far, [url http://www.binaryphile.com/bash/2018/07/26/approach-bash-like-a-developer-part-1-intro.html there are benefits, especially when approaching it seriously].
+But I believe that is a step too far, {url there are benefits, especially when approaching it seriously;http://www.binaryphile.com/bash/2018/07/26/approach-bash-like-a-developer-part-1-intro.html}.
Every language has mind-numbing oddities, some get the out of the way from the start (like BASH), and others much later.
+
+{footnotes}
diff --git a/src/blog/connect-to-mysql-in-dotnet-ef/index.du b/src/blog/connect-to-mysql-in-dotnet-ef/index.du
index e745f16..d1c48ab 100644
--- a/src/blog/connect-to-mysql-in-dotnet-ef/index.du
+++ b/src/blog/connect-to-mysql-in-dotnet-ef/index.du
@@ -1,66 +1,68 @@
-# Connect to MySql in .NET and Entity Framework
+'def title Connect to MySql in .NET and Entity Framework
+'def desc Connecting a .NET application to a MySql database (with Entity Framework) can be tricky. Here is what works for me.
-'define expected-reading 3 min
-'define created 21 May 2020
-'define edited 19 June 2021
-[$pagenav]
+# {title}
+
+{pagenav 3 min;21 May 2020;19 June 2021}
:contents
.numbered
-1. [url #nuget-packages NuGet packages]
-2. [url #connection-string Connection string]
-3. [url #connecting Connecting]
+1. {uhref NuGet packages}
+2. {uhref Connection string}
+3. {uhref Connecting}
.numbered
- 1. [url #asp.net-startup ASP.NET Startup]
- 2. [url #dbcontext-child-class DBContext child class]
+ 1. {uhref ASP.NET Startup}
+ 2. {uhref DBContext child class}
-I have found that connecting a [`.NET`] application to a [`MySql`] database (with Entity Framework) can be tricky. Here is what works for me.
+I have found that connecting a {` .NET} application to a {` MySql} database (with Entity Framework) can be tricky. Here is what works for me.
-Also, [url https://www.nuget.org/packages/MySql.Data.EntityFrameworkCore/ MySql.Data.EntityFrameworkCore] has been [=depricated=] since [*October 2020*]. If you need setup instructions with it, read [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/0510e29526c6d7681587fff4c98a339e8c69e9b5/src/blog/connect-to-mysql-in-csharp-ef/article.md this].
+Also, {url MySql.Data.EntityFrameworkCore;https://www.nuget.org/packages/MySql.Data.EntityFrameworkCore/} has been {b depricated} since {i October 2020}. If you need setup instructions with it, read {url this;https://gitlab.com/Syndamia/syndamiadotcom/-/blob/0510e29526c6d7681587fff4c98a339e8c69e9b5/src/blog/connect-to-mysql-in-csharp-ef/article.md}.
## NuGet packages
-You'll need to install [url https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql/ Pomelo.EntityFrameworkCore.MySql]. It provides the stuff necessary for connecting and using a [`MySql`] database.
+You'll need to install {url Pomelo.EntityFrameworkCore.MySql;https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql/}. It provides the stuff necessary for connecting and using a {` MySql} database.
## Connection string
-There are [url https://www.connectionstrings.com/mysql/ a lot] of ways to setup the connection string but I've found that this one works the best:
+There are {url a lot;https://www.connectionstrings.com/mysql/} of ways to setup the connection string but I've found that this one works the best:
```
"server=localhost; port=YOUR-PORT; user id=YOUR-USER-ID; password=YOUR-PASSWORD; database=NAME-OF-DATABASE; SslMode=none"
-If you are using [`MySQL Workbench`] and you don't know your port and id, you can look at the server information from the [`MySQL Connections`] page.
+If you are using {` MySQL Workbench} and you don't know your port and id, you can look at the server information from the {` MySQL Connections} page.
-[image ./img/connections.png MyServer root 127.0.0.1:3306] In this example, the user id is _root_ and the port is _3306_.
+{img MyServer root 127.0.0.1:3306;./img/connections.png} In this example, the user id is _root_ and the port is _3306_.
## Connecting
-To connect, you'll need to call the [`UseMySql`] method, either in [url #asp.net-startup ASP.NET Startup] or in a [url #dbcontext-child-class DBContext child class].
+To connect, you'll need to call the {` UseMySql} method, either in {url ASP.NET Startup;#asp.net-startup} or in a {url DBContext child class;#dbcontext-child-class}.
-The method requires at least two arguments: connection string and [`MySql`] server version. The latter you can find, by going to the [`Help/About Workbench`] window inside [`MySQL Workbench`].
+The method requires at least two arguments: connection string and {` MySql} server version. The latter you can find, by going to the {` Help/About Workbench} window inside {` MySQL Workbench}.
-[image ./img/about-workbench.png]
-[image ./img/workbench-version.png]
+{img ./img/about-workbench.png}
+{img ./img/workbench-version.png}
-For the server version argument, create a new object of type [`MySqlServerVersion`] and give it's constructor a new object of type [`Version`], to which you give the version numbers. The result should look something like this:
+For the server version argument, create a new object of type {` MySqlServerVersion} and give it's constructor a new object of type {` Version}, to which you give the version numbers. The result should look something like this:
-```c#
+```csharp
+'emplace
.UseMySql(CONNECTION_STRING, new MySqlServerVersion(new System.Version(8, 0, 21)))
+'endemplace
-Where [`CONNECTION_STRING`] is a (constant) variable that contains your connection string, and 8, 0, 21 are the version numbers.
+Where {` CONNECTION_STRING} is a (constant) variable that contains your connection string, and 8, 0, 21 are the version numbers.
### ASP.NET Startup
-For [`ASP.NET`] applications, the connection must be put inside the [`ConfigureServices`] method of the [`Startup.cs`] file. If you already have a [`.UseSQL`] method call in there, just replace it with your [`.UseMySql`] method and arguments.
+For {` ASP.NET} applications, the connection must be put inside the {` ConfigureServices} method of the {` Startup.cs} file. If you already have a {` .UseSQL} method call in there, just replace it with your {` .UseMySql} method and arguments.
The result should look something along the lines of:
-```c#
+```csharp
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
- ...
+ \...
services.AddDbContext<AppDbContext>(opt =>
{
opt.UseMySql(...);
@@ -69,9 +71,9 @@ public void ConfigureServices(IServiceCollection services)
### DBContext child class
-Another way to connect is via a [`DBContext`] child class (so, inside your own DB context). Just, override the [`OnConfiguring`] method and call the [`.UseMySql`] method from the [`optionsBuilder`] parameter.
+Another way to connect is via a {` DBContext} child class (so, inside your own DB context). Just, override the {` OnConfiguring} method and call the {` .UseMySql} method from the {` optionsBuilder} parameter.
-```c#
+```csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySql(...);
diff --git a/src/blog/disable-sticky-keys-popup/index.du b/src/blog/disable-sticky-keys-popup/index.du
index a51a7a1..ccacd9e 100644
--- a/src/blog/disable-sticky-keys-popup/index.du
+++ b/src/blog/disable-sticky-keys-popup/index.du
@@ -1,31 +1,31 @@
-# How to disable Sticky Keys prompt
+'def title How to disable Sticky Keys prompt
+'def desc Quick and easy instructions on disabling the Windows prompt 'Do you want to turn on Sticky Keys?'
-'define expected-reading 1 min
-'define created 01 November 2021
-'define edited 01 November 2021
-[$pagenav]
+# {title}
-We've all been there: you're playing a game and after pressing [`Shift`] multiple times, you get a popup about "Sticky Keys", similar to this one:
+{pagenav 1 min;01 November 2021;01 November 2021}
-[image ./img/windows-sticky-keys-prompt.png]
+We've all been there: you're playing a game and after pressing {` Shift} multiple times, you get a popup about "Sticky Keys", similar to this one:
+
+{img ./img/windows-sticky-keys-prompt.png}
This is how to stop the popup from showing up ever again:
:ordered
-1. Press [=Windows key + R=], type in [`control access.cpl`], and then press [=OK=]
+1. Press {b Windows key + R}, type in {` control access.cpl}, and then press {b OK}
- [image ./img/windows-run-control-access.png]
+ {img ./img/windows-run-control-access.png}
-2. Inside the opened up window, press [=Make the keyboard easier to use=]
+2. Inside the opened up window, press {b Make the keyboard easier to use}
- [image ./img/windows-make-keyboard-highlighted.png]
+ {img ./img/windows-make-keyboard-highlighted.png}
-3. After that, press [=Set up Sticky Keys=]
+3. After that, press {b Set up Sticky Keys}
- [image ./img/windows-sticky-keys-highlighted.png]
+ {img ./img/windows-sticky-keys-highlighted.png}
-4. Uncheck the [=Turn on Sticky Keys when SHIFT is pressed five times=]
+4. Uncheck the {b Turn on Sticky Keys when SHIFT is pressed five times}
- [image ./img/windows-sticky-keys-disable.png]
+ {img ./img/windows-sticky-keys-disable.png}
-5. Finally, press [=OK=] and close the window
+5. Finally, press {b OK} and close the window
diff --git a/src/blog/encrypted-email/index.du b/src/blog/encrypted-email/index.du
index 4ed85d7..5c32917 100644
--- a/src/blog/encrypted-email/index.du
+++ b/src/blog/encrypted-email/index.du
@@ -1,69 +1,69 @@
-# Encrypted email
+'def title Encrypted email
+'def desc Outlining and explanation of encrypted email systems
-'define expected-reading 10 min
-'define created 10 September 2022
-'define edited 16 September 2022
-[$pagenav]
+# {title}
+
+{pagenav 10 min;10 September 2022;16 September 2022}
:contents
:numbered
-1. [url #encryption-and-signature Encryption and signature]
-2. [url #openpgp OpenPGP]
+1. {uhref Encryption and signature}
+2. {uhref OpenPGP}
.numbered
- 1. [url #pgpinline PGP/Inline]
- 2. [url #pgpmime PGP/MIME]
+ 1. {uhref PGP/Inline}
+ 2. {uhref PGP/MIME}
-3. [url #smime S/MIME]
-4. [url #reop reop]
-5. [url #post-email-systems Post-email systems]
-6. [url #centralized-non-email-systems Centralized non-email systems]
+3. {uhref S/MIME}
+4. {uhref reop}
+5. {uhref Post-email systems}
+6. {uhref Centralized non-email systems}
.numbered
- 1. [url #protonmail Protonmail]
- 2. [url #tutanota Tutanota]
+ 1. {uhref Protonmail}
+ 2. {uhref Tutanota}
-7. [url #conclusion Conclusion]
+7. {uhref Conclusion}
-When you try and look around for articles, regarding encrypted emails, all you'll find is people complaining about it's difficulties and shortcomings. But, no one actually explains what to do if you, nevertheless, want to encrypt your emails! At best most articles will just [url https://www.virtru.com/blog/arent-people-using-email-encryption shove some product up your face].
+When you try and look around for articles, regarding encrypted emails, all you'll find is people complaining about it's difficulties and shortcomings. But, no one actually explains what to do if you, nevertheless, want to encrypt your emails! At best most articles will just {url shove some product up your face;https://www.virtru.com/blog/arent-people-using-email-encryption}.
-That's why, after a fairly lengthy research process, I've decided to do just that. These are the more common ways to encrypt your email with their strengths and weaknesses. I also wrote a (somewhat rough) [url /blog/how-to-encrypt-email tutorial on how to setup] [url #openpgp OpenPGP] or [url #smime S/MIME] in practice.
+That's why, after a fairly lengthy research process, I've decided to do just that. These are the more common ways to encrypt your email with their strengths and weaknesses. I also wrote a (somewhat rough) {url tutorial on how to setup;/blog/how-to-encrypt-email} {url OpenPGP;#openpgp} or {url S/MIME;#smime} in practice.
-[*Note:*] What I'm referring to is end-to-end encryption, where you send an encrypted email, and the recipient decrypts it. Encryption between you and a mail server is practically a given and is setup by the mail server administrator.
+{i Note:} What I'm referring to is end-to-end encryption, where you send an encrypted email, and the recipient decrypts it. Encryption between you and a mail server is practically a given and is setup by the mail server administrator.
## Encryption and signature
-Unless stated otherwise, all of the listed encryption (and signature) schemes work by utilizing [url https://en.wikipedia.org/wiki/Public-key_cryptography public-key cryptography].
+Unless stated otherwise, all of the listed encryption (and signature) schemes work by utilizing {url public-key cryptography;https://en.wikipedia.org/wiki/Public-key_cryptography}.
-In brief, if you are sending an encrypted email, the [=recipient=] needs to have generated a public and private key pair. Then you need to have acquired [=their public key=]. Finally, if you want to send them an encrypted email:
+In brief, if you are sending an encrypted email, the {b recipient} needs to have generated a public and private key pair. Then you need to have acquired {b their public key}. Finally, if you want to send them an encrypted email:
.numbered
-1. You encrypt [=your=] email with [=their public key=]
-2. The recipient decrypts [=your=] message with [=their private key=]
+1. You encrypt {b your} email with {b their public key}
+2. The recipient decrypts {b your} message with {b their private key}
-And if someone wants to send [=you=] an encrypted email, [=you=] need to generate a public and private key pair, share [=your public key=] with them, and when you receive the message, decrypt it with [=your private key=].
+And if someone wants to send {b you} an encrypted email, {b you} need to generate a public and private key pair, share {b your public key} with them, and when you receive the message, decrypt it with {b your private key}.
-Every email you send can be [url https://en.wikipedia.org/wiki/Digital_signature digitally signed] (not to be confused with [url https://en.wikipedia.org/wiki/Digital_signature electronic signatures]), meaning the message is (cryptographically) "signed", and with this signature, the recipient can check if the message was changed during transit. Digital signatures also use public-key cryptography, but the other way around:
+Every email you send can be {url digitally signed;https://en.wikipedia.org/wiki/Digital_signature} (not to be confused with {url electronic signatures;https://en.wikipedia.org/wiki/Digital_signature}), meaning the message is (cryptographically) "signed", and with this signature, the recipient can check if the message was changed during transit. Digital signatures also use public-key cryptography, but the other way around:
.numbered
-1. You sign [=your=] email with [=your private key=]
-2. Then the recipient verifies [=your=] message with [=your public key=].
+1. You sign {b your} email with {b your private key}
+2. Then the recipient verifies {b your} message with {b your public key}.
-This might sound a bit complicated, but all you need to worry about is you and the recipient generating these public-private key pairs, exchanging public keys, and your email client should handle the rest. And if you use a tool like [url https://www.pep.security/en/ pEp], the creation and exchange of keys can be easily automated.
+This might sound a bit complicated, but all you need to worry about is you and the recipient generating these public-private key pairs, exchanging public keys, and your email client should handle the rest. And if you use a tool like {url pEp;https://www.pep.security/en/}, the creation and exchange of keys can be easily automated.
## OpenPGP
-By far, the most popular way to encrypt your emails is with [url https://en.wikipedia.org/wiki/Pretty_Good_Privacy OpenPGP]. PGP is the original program which implemented the encryption scheme, while OpenPGP is the standard/encryption scheme, which was created from PGP (so when I say OpenPGP, I mean a program that implements OpenPGP).
+By far, the most popular way to encrypt your emails is with {url OpenPGP;https://en.wikipedia.org/wiki/Pretty_Good_Privacy}. PGP is the original program which implemented the encryption scheme, while OpenPGP is the standard/encryption scheme, which was created from PGP (so when I say OpenPGP, I mean a program that implements OpenPGP).
-By design, it relies on a [url https://en.wikipedia.org/wiki/Web_of_trust web of trust], the idea being, different people sign each others public keys (sometimes at [url https://en.wikipedia.org/wiki/Key_signing_party key signing parties]), and you know that a specific key corresponds to a specific person, only when a large amount of people have signed it.
+By design, it relies on a {url web of trust;https://en.wikipedia.org/wiki/Web_of_trust}, the idea being, different people sign each others public keys (sometimes at {url key signing parties;https://en.wikipedia.org/wiki/Key_signing_party}), and you know that a specific key corresponds to a specific person, only when a large amount of people have signed it.
-OpenPGP divides the security community quite a lot, some [url https://restoreprivacy.com/let-pgp-die/ abolish it] while other still [url https://arstechnica.com/information-technology/2016/12/signal-does-not-replace-pgp/ defend it], but at the end of the day, it's very widespread and if someone encrypts their email, chances are it's with OpenPGP (unless they're in a business, where [url #smime S/MIME] rules).
+OpenPGP divides the security community quite a lot, some {url abolish it;https://restoreprivacy.com/let-pgp-die/} while other still {url defend it;https://arstechnica.com/information-technology/2016/12/signal-does-not-replace-pgp/}, but at the end of the day, it's very widespread and if someone encrypts their email, chances are it's with OpenPGP (unless they're in a business, where {url S/MIME;#smime} rules).
There are two main ways to encrypt an email with OpenPGP:
### PGP/Inline
-The first is called "PGP/Inline", with which you encrypt only the message itself. That's it. And there are [url https://josefsson.org/inline-openpgp-considered-harmful.html other limitations] too, to name a few:
+The first is called "PGP/Inline", with which you encrypt only the message itself. That's it. And there are {url other limitations;https://josefsson.org/inline-openpgp-considered-harmful.html} too, to name a few:
.numbered
1. You can't encrypt attachments, period.
@@ -73,67 +73,67 @@ Though, it's not all bad. If you can survive only sending text to other people,
.numbered
1. It's much easier to work with, you can directly copy the encrypted PGP message and decrypt it however you like
-2. The other option, PGP/MIME, is much harder to implement properly and there have been cases where [url https://web.archive.org/web/20180625054201/https://www.whonix.org/blog/pgp-inline-vs-mime it's implementation is flawed]
+2. The other option, PGP/MIME, is much harder to implement properly and there have been cases where {url it's implementation is flawed;https://web.archive.org/web/20180625054201/https://www.whonix.org/blog/pgp-inline-vs-mime}
### PGP/MIME
-"PGP/MIME" is the second option. As it's name suggests, you can encrypt [url https://en.wikipedia.org/wiki/MIME MIME] data with PGP, which by definition means it supports any content type. This includes:
+"PGP/MIME" is the second option. As it's name suggests, you can encrypt {url MIME;https://en.wikipedia.org/wiki/MIME} data with PGP, which by definition means it supports any content type. This includes:
.numbered
1. Support for Unicode characters and HTML messages
2. Attachments of any type
3. Delivery status report
-Basically, any [url https://en.wikipedia.org/wiki/MIME#Multipart_subtypes multipart subtype]. Also, I should mention, the message structure and all metadata is hidden by design.
+Basically, any {url multipart subtype;https://en.wikipedia.org/wiki/MIME#Multipart_subtypes}. Also, I should mention, the message structure and all metadata is hidden by design.
-PGP/MIME is capable of a lot more, and is [url https://www.mailpile.is/blog/2014-11-21_To_PGP_MIME_Or_Not.html generally preferred] over PGP/Inline. Nonetheless, it has it's shortcomings:
+PGP/MIME is capable of a lot more, and is {url generally preferred;https://www.mailpile.is/blog/2014-11-21_To_PGP_MIME_Or_Not.html} over PGP/Inline. Nonetheless, it has it's shortcomings:
.numbered
-1. As already mentioned, it is hard to implement and [url https://web.archive.org/web/20180625054201/https://www.whonix.org/blog/pgp-inline-vs-mime flawed implementations] have been made
+1. As already mentioned, it is hard to implement and {url flawed implementations;https://web.archive.org/web/20180625054201/https://www.whonix.org/blog/pgp-inline-vs-mime} have been made
2. Everything is encrypted together, so you'll need to download the whole email, including all attachments, to decrypt it
3. If your client doesn't support it, manual decryption takes a bit more work
## S/MIME
-[url https://en.wikipedia.org/wiki/S/MIME S/MIME], roughly said, combines and extends the [url https://en.wikipedia.org/wiki/Cryptographic_Message_Syntax Cryptograhic Message Syntax] encryption scheme and [url https://en.wikipedia.org/wiki/MIME MIME] standard to create a singular, email-oriented standard.
+{url S/MIME;https://en.wikipedia.org/wiki/S/MIME}, roughly said, combines and extends the {url Cryptograhic Message Syntax;https://en.wikipedia.org/wiki/Cryptographic_Message_Syntax} encryption scheme and {url MIME;https://en.wikipedia.org/wiki/MIME} standard to create a singular, email-oriented standard.
-Unlike OpenPGP it doesn't use a web of trust, but a [url https://en.wikipedia.org/wiki/Public_key_infrastructure Public key infrastructure]. This means that, rather than people exchanging certificates between themselves, a [url https://en.wikipedia.org/wiki/Certificate_authority Certificate Authroity] connects public keys with entities (people or organizations for example).
+Unlike OpenPGP it doesn't use a web of trust, but a {url Public key infrastructure;https://en.wikipedia.org/wiki/Public_key_infrastructure}. This means that, rather than people exchanging certificates between themselves, a {url Certificate Authroity;https://en.wikipedia.org/wiki/Certificate_authority} connects public keys with entities (people or organizations for example).
-So, already, it has a huge advantage, you don't need to exchange keys, since the email client will handle it. S/MIME is most often used by corporations/organizations, so support in commercial mail clients like [url https://support.google.com/a/answer/6374496?hl=en#zippy= Google Workspace Enterprise Edition] and [url https://support.microsoft.com/en-us/office/encrypt-messages-by-using-s-mime-in-outlook-on-the-web-878c79fc-7088-4b39-966f-14512658f480 Outlook Enterprise/Business] ([url https://docs.microsoft.com/en-us/exchange/security-and-compliance/smime-exo/configure-smime-exo?view=o365-worldwide Exchange Online has to be configured] by an administrator and can be used only with [url https://docs.microsoft.com/en-us/deployoffice/endofsupport/microsoft-365-services-connectivity paid clients]) is available.
+So, already, it has a huge advantage, you don't need to exchange keys, since the email client will handle it. S/MIME is most often used by corporations/organizations, so support in commercial mail clients like {url Google Workspace Enterprise Edition;https://support.google.com/a/answer/6374496?hl=en#zippy=} and {url Outlook Enterprise/Business;https://support.microsoft.com/en-us/office/encrypt-messages-by-using-s-mime-in-outlook-on-the-web-878c79fc-7088-4b39-966f-14512658f480} ({url Exchange Online has to be configured;https://docs.microsoft.com/en-us/exchange/security-and-compliance/smime-exo/configure-smime-exo?view=o365-worldwide} by an administrator and can be used only with {url paid clients;https://docs.microsoft.com/en-us/deployoffice/endofsupport/microsoft-365-services-connectivity}) is available.
-On the other hand, you can browse [url https://support.google.com/a/answer/7448393?hl=en&ref_topic=9061730 Google's] and [url https://docs.microsoft.com/en-us/security/trusted-root/participants-list Microsoft's] trusted (root) CAs all you want, but you'll find that there is only one place where you could register a certificate for free: [url https://www.actalis.com/s-mime-certificates.aspx Actalis]. A good tutorial on the procedure can be found [url https://www.dannyguo.com/blog/how-to-get-a-free-s-mime-certificate/ here], but beware, [*they*] generate the private key.
+On the other hand, you can browse {url Google's;https://support.google.com/a/answer/7448393?hl=en&ref_topic=9061730} and {url Microsoft's;https://docs.microsoft.com/en-us/security/trusted-root/participants-list} trusted (root) CAs all you want, but you'll find that there is only one place where you could register a certificate for free: {url Actalis;https://www.actalis.com/s-mime-certificates.aspx}. A good tutorial on the procedure can be found {url here;https://www.dannyguo.com/blog/how-to-get-a-free-s-mime-certificate/}, but beware, {i they} generate the private key.
-Otherwise, it's email encryption capabilities are the same as those outlined in [url #pgpmime PGP/MIME].
+Otherwise, it's email encryption capabilities are the same as those outlined in {url PGP/MIME;#pgpmime}.
## reop
-[url https://flak.tedunangst.com/post/reop reop] is a very new, simple and "completed" system. The thing is, it's only a single command line utility that uses some encryption schemes (picked by the [url http://nacl.cr.yp.to/index.html nacl] library) for it's own unique system. Currently, there doesn't seem to be any email clients that support it.
+{url reop;https://flak.tedunangst.com/post/reop} is a very new, simple and "completed" system. The thing is, it's only a single command line utility that uses some encryption schemes (picked by the {url nacl;http://nacl.cr.yp.to/index.html} library) for it's own unique system. Currently, there doesn't seem to be any email clients that support it.
It is also fairly limited:
.quote
no support for key revocation, or long chains of certificates, or partial trust, or key servers
-However, as explained in it's [url https://flak.tedunangst.com/post/reop article], that might not be that big of a deal. Finally, there are very very few people that use it. From experience, I have only seen [url https://hacktivis.me/about Haelwenn Monnier] use it.
+However, as explained in it's {url article;https://flak.tedunangst.com/post/reop}, that might not be that big of a deal. Finally, there are very very few people that use it. From experience, I have only seen {url Haelwenn Monnier;https://hacktivis.me/about} use it.
The only reason for using reop is if you want a very small system with a very simple source code behind it. Nevertheless, it's still a viable alternative.
## Post-email systems
-There is a somewhat old [url https://github.com/OpenTechFund/secure-email document], created by the [url https://www.opentech.fund/ OpenTechFunc], which outlines very thoroughly all "next generation secure email or email-like communication" technologies.
+There is a somewhat old {url document;https://github.com/OpenTechFund/secure-email}, created by the {url OpenTechFunc;https://www.opentech.fund/}, which outlines very thoroughly all "next generation secure email or email-like communication" technologies.
-In it, they define the term "[url https://github.com/OpenTechFund/secure-email#post-email-alternatives post-mail]" as:
+In it, they define the term "{url post-mail;https://github.com/OpenTechFund/secure-email#post-email-alternatives}" as:
.quote
projects to create alternatives to email that are more secure yet still email-like
-And outline zero trust and fingerprinting as the main advantages of these systems. Also most of these systems are [url https://en.wikipedia.org/wiki/Peer-to-peer peer-to-peer].
+And outline zero trust and fingerprinting as the main advantages of these systems. Also most of these systems are {url peer-to-peer;https://en.wikipedia.org/wiki/Peer-to-peer}.
-Given that these projects aren't really email, I won't dive much deeper into it. But I will mention, almost all listed projects seem to have been abandoned. Those still under active development are [url http://goldbug.sourceforge.net/ goldbug] and [url https://retroshare.cc/ retroshare]. Until 2021, zeronet [*was*] updated, but the [url https://github.com/shortcutme author] seems to have [url https://github.com/HelloZeroNet/ZeroNet/issues/2808#issuecomment-1132820787 disappeared].
+Given that these projects aren't really email, I won't dive much deeper into it. But I will mention, almost all listed projects seem to have been abandoned. Those still under active development are {url goldbug;http://goldbug.sourceforge.net/} and {url retroshare;https://retroshare.cc/}. Until 2021, zeronet {i was} updated, but the {url author;https://github.com/shortcutme} seems to have {url disappeared;https://github.com/HelloZeroNet/ZeroNet/issues/2808#issuecomment-1132820787}.
## Centralized non-email systems
-"Centralized non-email systems" is another term, which as far as I can tell, is also coined by [url https://github.com/OpenTechFund/secure-email this document] from [url https://www.opentech.fund/ OpenTechFunc]. They define it as "centralized email-like messaging platform" and further divide it into:
+"Centralized non-email systems" is another term, which as far as I can tell, is also coined by {url this document;https://github.com/OpenTechFund/secure-email} from {url OpenTechFunc;https://www.opentech.fund/}. They define it as "centralized email-like messaging platform" and further divide it into:
:quote
:numbered
@@ -147,28 +147,28 @@ Given that these projects aren't really email, I won't dive much deeper into it.
-Out of the listed options, Enlocked doesn't work anymore and was [url https://adammonsen.com/post/853/ a bad system] to begin with, ShazzleMail is pretty much [url https://www.reddit.com/r/privacytoolsIO/comments/nv6gzu/comment/hf338kq/?utm_source=share&utm_medium=web2x&context=3 dead] and Walnut also isn't up.
+Out of the listed options, Enlocked doesn't work anymore and was {url a bad system;https://adammonsen.com/post/853/} to begin with, ShazzleMail is pretty much {url dead;https://www.reddit.com/r/privacytoolsIO/comments/nv6gzu/comment/hf338kq/?utm_source=share&utm_medium=web2x&context=3} and Walnut also isn't up.
That leaves us with the two last-standing providers:
### Protonmail
-Protonmail, or [url https://proton.me/ proton.me] as they are called now, which uses good old [url #openpgp OpenPGP]. That means they have end-to-end encryption and zero-access encryption by default for all protonmail accounts. They also [url https://proton.me/support/how-to-use-pgp support encrypted conversations with non-protonmail users].
+Protonmail, or {url proton.me;https://proton.me/} as they are called now, which uses good old {url OpenPGP;#openpgp}. That means they have end-to-end encryption and zero-access encryption by default for all protonmail accounts. They also {url support encrypted conversations with non-protonmail users;https://proton.me/support/how-to-use-pgp}.
-Funnily enough, Protonmail doesn't really fit in any of the listed categories, since encrypted emails outside the system will work as any [url #openpgp OpenPGP] encrypted one.
+Funnily enough, Protonmail doesn't really fit in any of the listed categories, since encrypted emails outside the system will work as any {url OpenPGP;#openpgp} encrypted one.
-Protonmail's services have a free tier, which should be enough for lighter usage, but restricts [=heavily=] storage, label and folder count, amount of sent messages per day, etc. At the time of writing, their second tier pretty much lifts all restrictions for 5 euro per month (without annual contracts). Check out their pricing [url https://proton.me/pricing here].
+Protonmail's services have a free tier, which should be enough for lighter usage, but restricts {b heavily} storage, label and folder count, amount of sent messages per day, etc. At the time of writing, their second tier pretty much lifts all restrictions for 5 euro per month (without annual contracts). Check out their pricing {url here;https://proton.me/pricing}.
### Tutanota
-[url https://tutanota.com/ Tutanota] uses it's own special system for security. In brief, all of your emails are (zero-access) stored and end-to-end encrypted with (mostly) [url https://en.wikipedia.org/wiki/Advanced_Encryption_Standard AES 128], and while they generate and hold your public and private keys, your password is needed to decrypt your private key (do check out their [url https://tutanota.com/security/ security page] for more details).
+{url Tutanota;https://tutanota.com/} uses it's own special system for security. In brief, all of your emails are (zero-access) stored and end-to-end encrypted with (mostly) {url AES 128;https://en.wikipedia.org/wiki/Advanced_Encryption_Standard}, and while they generate and hold your public and private keys, your password is needed to decrypt your private key (do check out their {url security page;https://tutanota.com/security/} for more details).
-However, it's crucial to note that they are a type [*2. Semi-closed system*]. If you send an encrypted email to a non-tutanota recipient, the recipient will get a URL from which they will be able to reply, through Tutanota's web client.
+However, it's crucial to note that they are a type {i 2. Semi-closed system}. If you send an encrypted email to a non-tutanota recipient, the recipient will get a URL from which they will be able to reply, through Tutanota's web client.
-Finally, pricing. In general, they have a lot less features than [url #protonmail Protonmail], but their free tier is a lot more capable than [url #protonmail Protonmail]'s. Their pricing is extremely flexible, being able to buy specific features by themselves, like storage or mail aliases. Check it out [url https://tutanota.com/pricing/ here].
+Finally, pricing. In general, they have a lot less features than {url Protonmail;#protonmail}, but their free tier is a lot more capable than {url Protonmail;#protonmail}'s. Their pricing is extremely flexible, being able to buy specific features by themselves, like storage or mail aliases. Check it out {url here;https://tutanota.com/pricing/}.
## Conclusion
-In brief, almost all email encryption systems use [url #encryption-and-signature public-key cryptography]. The most popular of these systems for personal use is [url #openpgp OpenPGP], but in the business space, [url #smime S/MIME] is quite a bit more prominent. [url #reop reop] is a viable, but limited, very new and lightweight systems for encrypting your email messages.
+In brief, almost all email encryption systems use {url public-key cryptography;#encryption-and-signature}. The most popular of these systems for personal use is {url OpenPGP;#openpgp}, but in the business space, {url S/MIME;#smime} is quite a bit more prominent. {url reop;#reop} is a viable, but limited, very new and lightweight systems for encrypting your email messages.
-[url #protonmail Protonmail] is an email provider, which has [url #openpgp OpenPGP] built-in, enabling and supporting encryption by default, but their free tier leaves what to be desired. [url #tutanota Tutanota] is another provider, with their own entirely different system, where encrypted emails to non-tutanota users force the recipients to use their web client.
+{url Protonmail;#protonmail} is an email provider, which has {url OpenPGP;#openpgp} built-in, enabling and supporting encryption by default, but their free tier leaves what to be desired. {url Tutanota;#tutanota} is another provider, with their own entirely different system, where encrypted emails to non-tutanota users force the recipients to use their web client.
diff --git a/src/blog/export-skype/index.du b/src/blog/export-skype/index.du
index 9f88ce7..be76ad6 100644
--- a/src/blog/export-skype/index.du
+++ b/src/blog/export-skype/index.du
@@ -1,15 +1,15 @@
-# How to export Skype data
+'def title How to export Skype data
+'def desc You navigate to Skype's data-export page, download your data, then you open it with Skype's official tool or with an improved fork of it.
-'define expected-reading 3 min
-'define created 03 October 2021
-'define edited 03 October 2021
-[$pagenav]
+# {title}
+
+{pagenav 3 min;03 October 2021;03 October 2021}
:contents
.numbered
-1. [url #downloading-files Downloading files]
-2. [url #viewing-your-export-official-tool Viewing your export - Official Tool]
-3. [url #viewing-your-export-artemveremienko-fork Viewing your export - ArtemVeremienko Fork]
+1. {uhref Downloading files}
+2. {uhref Viewing your export - Official Tool}
+3. {uhref Viewing your export - ArtemVeremienko Fork}
Skype has always allowed to export your chat history (and files), but it's not as straight forward as it should.
@@ -18,53 +18,53 @@ Continue reading for the required steps on doing it.
## Downloading files
:ordered
-1. Open [url https://secure.skype.com/en/data-export secure.skype.com/en/data-export]
+1. Open {url secure.skype.com/en/data-export;https://secure.skype.com/en/data-export}
.unordered
- You could be asked to sign in.
- After signing in you'll need to [*open the link again*], since you would be redirected to the wrong place.
+ After signing in you'll need to {i open the link again}, since you would be redirected to the wrong place.
2. After opening the link you should be greeted by something like this.
- Check the two checkboxes next to [=Conversations=] and [=Files=] [*(pointed to by the red arrows)*].
+ Check the two checkboxes next to {b Conversations} and {b Files} {i (pointed to by the red arrows)}.
- [image ./img/initial-screen.png]
+ {img ./img/initial-screen.png}
-3. Press [=Submit request=].
- After being greeted by this screen, press [=Continue=].
+3. Press {b Submit request}.
+ After being greeted by this screen, press {b Continue}.
- [image ./img/export-prepared.png]
+ {img ./img/export-prepared.png}
.bulleted
- - You should now see an [=Available exports=] section near the top of the page.
- The status will be [=Pending=].
- .p [image ./img/available-exports.png]
+ - You should now see an {b Available exports} section near the top of the page.
+ The status will be {b Pending}.
+ .p {img ./img/available-exports.png}
-5. Reload the page after a bit of time. When your export is ready, you'll find a [=Download=] button next to it, click it.
+5. Reload the page after a bit of time. When your export is ready, you'll find a {b Download} button next to it, click it.
- [image ./img/download-button.png]
+ {img ./img/download-button.png}
-Your export will be downloaded as a [`.tar`] archive file.
-You'll need an archiver utility to extract the files, something like [url https://www.rarlab.com/download.htm WinRAR] or [url https://www.7-zip.org/ 7-Zip] [*(I personally recommend 7-Zip, it is completely free (no need to worry about your [url https://youtu.be/fTgZRVVr3_Y infinite trial]) and works faster)*].
+Your export will be downloaded as a {` .tar} archive file.
+You'll need an archiver utility to extract the files, something like {url WinRAR;https://www.rarlab.com/download.htm} or {url 7-Zip;https://www.7-zip.org/} {i (I personally recommend 7-Zip, it is completely free (no need to worry about your {url infinite trial;https://youtu.be/fTgZRVVr3_Y}) and works faster)}.
## Viewing your export - Official Tool
:ordered
1. Extract your archive
-2. Open the [url https://go.skype.com/skype-parser Skype Parser Download], which will prompt you to save [`skype-parser.zip`]
+2. Open the {url Skype Parser Download;https://go.skype.com/skype-parser}, which will prompt you to save {` skype-parser.zip}
-3. Extract [`skype-parser.zip`]
+3. Extract {` skype-parser.zip}
-4. Inside the [`skype-parser`] folder, open [`index.html`] (it might be named just [`index`]). You'll be greeted by this page in your browser:
- [image ./img/default-skype-parser-index.png]
+4. Inside the {` skype-parser} folder, open {` index.html} (it might be named just {` index}). You'll be greeted by this page in your browser:
+ {img ./img/default-skype-parser-index.png}
-5. Click the [`Choose File`] option and select the [`messages.json`] (it might be named just [`messages`]) file from your export.
- [image ./img/choose-file.png]
+5. Click the {` Choose File} option and select the {` messages.json} (it might be named just {` messages}) file from your export.
+ {img ./img/choose-file.png}
-6. Press the [`Load`] button right below, and you're done.
+6. Press the {` Load} button right below, and you're done.
On the left side you have your conversations, and when opening one, your messages will be displayed to the right (just like in Skype itself)
- [image ./img/archived-conversations-skype-default.png]
+ {img ./img/archived-conversations-skype-default.png}
There is only one issue with this method - the official tool is somewhat broken.
@@ -74,15 +74,15 @@ The fix is using an alternative to the official tool.
## Viewing your export - ArtemVeremienko Fork
-[url https://github.com/ArtemVeremienko ArtemVeremienko] is a GitHub user that took the official parser and fixed it.
-Their source code can be found over at [url https://github.com/ArtemVeremienko/skype-parser github.com/ArtemVeremienko/skype-parser].
+{url ArtemVeremienko;https://github.com/ArtemVeremienko} is a GitHub user that took the official parser and fixed it.
+Their source code can be found over at {url github.com/ArtemVeremienko/skype-parser;https://github.com/ArtemVeremienko/skype-parser}.
:ordered
-1. Go to the [url https://github.com/ArtemVeremienko/skype-parser/releases/latest latest release of his skype-parser] and download [`skype-parser.zip`]
+1. Go to the {url latest release of his skype-parser;https://github.com/ArtemVeremienko/skype-parser/releases/latest} and download {` skype-parser.zip}
- [image ./img/github-skype-parser-download.png]
+ {img ./img/github-skype-parser-download.png}
2. Extract all of the files.
- They'll be in the same folder as the [`skype-parser.zip`] file, so find the [`index.html`] file and open it.
+ They'll be in the same folder as the {` skype-parser.zip} file, so find the {` index.html} file and open it.
-3. Continue from step 5 onward of the [url #viewing-your-export-official-tool Viewing your export - Official Tool] section
+3. Continue from step 5 onward of the {url Viewing your export - Official Tool;#viewing-your-export-official-tool} section
diff --git a/src/blog/fix-network-brother-printers/index.du b/src/blog/fix-network-brother-printers/index.du
index 045bb39..15a5126 100644
--- a/src/blog/fix-network-brother-printers/index.du
+++ b/src/blog/fix-network-brother-printers/index.du
@@ -1,28 +1,28 @@
-# Fix networked Brother printers not working in Linux
+'def title Fix networked Brother printers not working in Linux
+'def desc To fix a networked Brother printer under linux: check CUPS recongnises it on the network, check support, find drivers
-'define expected-reading 4 min
-'define created 28 June 2023
-'define edited 28 June 2023
-[$pagenav]
+# {title}
+
+{pagenav 4 min;28 June 2023;28 June 2023}
Before we start, make sure you have CUPS and avahi installed and running.
## Make sure CUPS recognises it
-Go to [url https://localhost:631/printers/ localhost:631/printers] and make sure your printer is listed there.
-If [=not=], go to [`Administration/Add Printer`] and select your printer.
-If it's [=not=] listed even there, then you have some other network connectivity issue.
+Go to {url localhost:631/printers;https://localhost:631/printers/} and make sure your printer is listed there.
+If {b not}, go to {` Administration/Add Printer} and select your printer.
+If it's {b not} listed even there, then you have some other network connectivity issue.
-Otherwise [url #try-to-print-a-test-page try to print a test page].
+Otherwise {url try to print a test page;#try-to-print-a-test-page}.
-### Check if it [=is=] recognised on the network.
+### Check if it {b is} recognised on the network.
Execute in the command line:
```bash
avahi-browse --all -t -r
-There will be a lot of output, but scroll down until you find something [*like*]:
+There will be a lot of output, but scroll down until you find something {i like}:
```
= enp0s25 IPv4 Brother HL-L2350DW series _pdl-datastream._tcp local
@@ -30,7 +30,7 @@ hostname = [BRW9C305B9EC83D.local]
address = [192.168.0.110]
The exact values aren't important, just make sure the part after IPv4 is the model of your printer.
-[`address`] is the local printer address, ping it.
+{` address} is the local printer address, ping it.
In this example, the command would be:
```bash
@@ -38,21 +38,21 @@ ping 192.168.0.110
.bulleted
- If the ping is successful, you might also want to put that IP address in your browser.
- With the example, you would open the link [`http://192.168.0.110`].
- Your printer [=may=] or [=may not=] support Web Based Management, which would allow you to edit it's setting from the browser.
+ With the example, you would open the link {` http://192.168.0.110}.
+ Your printer {b may} or {b may not} support Web Based Management, which would allow you to edit it's setting from the browser.
If the page isn't available, don't worry about it.
-If output is [=not=] something like [`64 bytes from ...`] (so, if it is [`Destination Host Unreachable`] or ping just hangs, without output), then it's an issue with your network or printer network configuration.
+If output is {b not} something like {` 64 bytes from ...} (so, if it is {` Destination Host Unreachable} or ping just hangs, without output), then it's an issue with your network or printer network configuration.
Make sure the printer is properly connected to the network.\n
Otherwise, this shows that your computer has network access to the printer, and all problems are local.
### Check if your printer is supported by Linux.
-Go to [url https://www.openprinting.org/printers www.openprinting.org/printers] and enter your model.
+Go to {url www.openprinting.org/printers;https://www.openprinting.org/printers} and enter your model.
If it isn't listed then it doesn't work for sure.
-Alternatively, if it is and the rating [url https://wiki.linuxfoundation.org/openprinting/database/databaseintro#about_the_data isn't "Perfectly"], then read the whole page, in case networking is listed as nonfunctional.
-If it [=is=] supported, then:
+Alternatively, if it is and the rating {url isn't "Perfectly";https://wiki.linuxfoundation.org/openprinting/database/databaseintro#about_the_data}, then read the whole page, in case networking is listed as nonfunctional.
+If it {b is} supported, then:
### Check if there are drivers available
@@ -61,8 +61,8 @@ Run in the command line:
```bash
lpinfo -v
-If you only get entries like [`network WORD`], without anything which looks like a URL (URI), then you may not have a working driver.
-Make sure you have installed any or tried all of the drivers listed in the printer's [url https://www.openprinting.org/printers www.openprinting.org] page.
+If you only get entries like {` network WORD}, without anything which looks like a URL (URI), then you may not have a working driver.
+Make sure you have installed any or tried all of the drivers listed in the printer's {url www.openprinting.org;https://www.openprinting.org/printers} page.
## Try to print a test page
@@ -73,7 +73,7 @@ After a little while, the "State" should change from "pending" to "processing" (
### Unable to locate printer "SOMETHING.local"
If you also have the error "Unable to locate printer "SOMETHING.local"." (obviously SOMETHING is the exact value you get), then that means the printer is accessed via the domain name "SOMETHING.local".
-[`.local`] domains require a special DNS server to be resolved, so inside [`/etc/nsswitch.conf`], on the line that starts with [`hosts`], add to it's end the value [`mdns_minimal`].
+{` .local} domains require a special DNS server to be resolved, so inside {` /etc/nsswitch.conf}, on the line that starts with {` hosts}, add to it's end the value {` mdns_minimal}.
It should look something like:
```
@@ -82,4 +82,4 @@ hosts: files dns mdns_minimal
After saving your changes, your printer should pretty quickly start printing the test page, no need to restart anything.
.bulleted
-- if your printer supports Web Based Management, then you should be able to go open the page [`http://SOMETHING.local`] in your browser and edit your printer settings from there.
+- if your printer supports Web Based Management, then you should be able to go open the page {` http://SOMETHING.local} in your browser and edit your printer settings from there.
diff --git a/src/blog/fix-no-frame-buffer-plan9/index.du b/src/blog/fix-no-frame-buffer-plan9/index.du
index 8d63c0b..fe21454 100644
--- a/src/blog/fix-no-frame-buffer-plan9/index.du
+++ b/src/blog/fix-no-frame-buffer-plan9/index.du
@@ -1,20 +1,20 @@
-# Fix "No frame buffer" error in Plan 9
+'def title Fix 'No frame buffer' error in Plan 9
+'def desc Installing Plan 9 by Bell Labs on QEMU/KVM might give an initdisplay error. To fix it, you'll need to change the monitor type from xga to vesa.
-'define expected-reading 3 min
-'define created 30 July 2022
-'define edited 30 July 2022
-[$pagenav]
+# {title}
-Let's say you installed [url https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs Plan 9 by Bell Labs] on a QEMU/KVM virtual machine by just following the prompts and entering defaults. In certain cases, you might find your install booting to a shell with the errors:
+{pagenav 3 min;30 July 2022;30 July 2022}
+
+Let's say you installed {url Plan 9 by Bell Labs;https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs} on a QEMU/KVM virtual machine by just following the prompts and entering defaults. In certain cases, you might find your install booting to a shell with the errors:
```
aux/vga: inportl(0xc100): permission denied
rio: can't open display: initdisplay: /dev/draw/new: no frame buffer
init: rc exit status: rio 31: display open
-[image ./img/boot-prompt-no-frame-buffer-error.png]
+{img ./img/boot-prompt-no-frame-buffer-error.png}
-For some reason, on certain configurations, the [`xga`] ([`vga`]) monitor type does not work when booting into Plan 9, even though it works fine during install. The fix is to adjust monitor settings to [`vesa`]:
+For some reason, on certain configurations, the {` xga} ({` vga}) monitor type does not work when booting into Plan 9, even though it works fine during install. The fix is to adjust monitor settings to {` vesa}:
:ordered
1. In the shell prompt enter
@@ -22,9 +22,10 @@ For some reason, on certain configurations, the [`xga`] ([`vga`]) monitor type d
```
aux/vga -m vesa -l
+ .p
You should get a cursor and a cleared prompt.
- [image ./img/manual-prompt.png]
+ {img ./img/manual-prompt.png}
2. In this "new" shell prompt, enter
@@ -33,7 +34,7 @@ rio
You should now get a grey background with the cursor in it.
- [image ./img/manual-rio.png]
+ {img ./img/manual-rio.png}
.bulleted
- You are now in a graphical environment, so technically you can stop here. The other steps are for configuring it so you wont ever have that problem again.
@@ -50,7 +51,7 @@ sam /n/9fat/plan9.ini
this is the configuration file we will be changing.
- [image ./img/rio-9fat-commands.png]
+ {img ./img/rio-9fat-commands.png}
.bulleted
- How to make a window: right click, hold, hover over "New" and release the right click. Now right click somewhere in the top left, hold, drag to somewhere in bottom right, release.
@@ -62,12 +63,12 @@ sam /n/9fat/plan9.ini
b /n/9fat/plan9.ini
and click the green-backgrounded box.
- Then replace [`xga`] with [`vesa`]:
+ Then replace {` xga} with {` vesa}:
```
, x/xga/ s/xga/vesa
- and click the green-backgrounded box again. We're almost done here, enter [`w`], wait a bit, and finally enter [`q`].
+ and click the green-backgrounded box again. We're almost done here, enter {` w}, wait a bit, and finally enter {` q}.
:unordered
- If you want to check whether the file was properly saved, feel free to run
@@ -77,14 +78,14 @@ cat /n/9fat/plan9.ini
and check that monitor is equal to vesa (you can scroll with the arrow keys, or with left and right mouse buttons, acting as up and down).
- [image ./img/rio-plan9ini-cat.png]
+ {img ./img/rio-plan9ini-cat.png}
- - The first command opens the [`plan9.ini`] file for editing, and the second command, finds every line that contains [`xga`] (there should probably be only one) and on each matching line replaces [`xga`] with [`vesa`]. Refer to the [url https://p9f.org/sys/doc/sam/sam.html docs] for more information.
+ - The first command opens the {` plan9.ini} file for editing, and the second command, finds every line that contains {` xga} (there should probably be only one) and on each matching line replaces {` xga} with {` vesa}. Refer to the {url docs;https://p9f.org/sys/doc/sam/sam.html} for more information.
-5. That's it, all we have to do is halt our file system with [`fshalt`] (or type out the command in the [url https://9p.io/wiki/plan9/Installing_Plan_9_on_Qemu/ Qemu installation guide]) and Force Reset the virtual machine.
+5. That's it, all we have to do is halt our file system with {` fshalt} (or type out the command in the {url Qemu installation guide;https://9p.io/wiki/plan9/Installing_Plan_9_on_Qemu/}) and Force Reset the virtual machine.
The next time you boot into Plan 9 and into your user, the graphical environment should load fine. Enjoy Plan 9!
-[image ./img/rio-default-login.png]
+{img ./img/rio-default-login.png}
diff --git a/src/blog/fix-qc-timeout/index.du b/src/blog/fix-qc-timeout/index.du
index 11dfa32..42ee9c1 100644
--- a/src/blog/fix-qc-timeout/index.du
+++ b/src/blog/fix-qc-timeout/index.du
@@ -1,12 +1,12 @@
-# Fix "qc timeout" kernel log error
+'def title Fix 'qc timeout' kernel log error
+'def desc Depending on your harddrive, you may get a 15 second boot delay, cause by a qc timeout error. The solution is to tell the kernel that DMA logs are not supported.
-'define expected-reading 4 min
-'define created 16 December 2023
-'define edited 20 August 2025
-[$pagenav]
+# {title}
+
+{pagenav 4 min;16 December 2023;20 August 2025}
Depending on your harddrive, you may get a 15 second delay on boot.
-Looking at the kernel logs (with [`dmesg`]), you may find the following errors:
+Looking at the kernel logs (with {` dmesg}), you may find the following errors:
```
kernel: ata1.00: qc timeout after 15000 msecs (cmd 0x47)
@@ -23,13 +23,13 @@ Meaning, add the following parameter:
```
libata.force=1.00:nodmalog
-where [`1.00`] is the thing between "ata" and ":".
+where {` 1.00} is the thing between "ata" and ":".
So, if your logs were
```
kernel: ata3.01: qc timeout after 15000 msecs (cmd 0x47)
-...
+\...
then the parameter would be:
@@ -42,7 +42,7 @@ libata.force=3.01:nodmalog
### Update 20 August 2025
.p
-About a month ago I stumbled upon this [url https://de.comp.hardware.laufwerke.festplatten.narkive.com/F8WstP5i/fix-frage-zu-sata-read-log-0x00-page-0x00-failed-emask-0x40 mailing list] (Google-powered translation to English [url https://de-comp-hardware-laufwerke-festplatten-narkive-com.translate.goog/F8WstP5i/fix-frage-zu-sata-read-log-0x00-page-0x00-failed-emask-0x40?_x_tr_sl=bg&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp here]).
+About a month ago I stumbled upon this {url mailing list;https://de.comp.hardware.laufwerke.festplatten.narkive.com/F8WstP5i/fix-frage-zu-sata-read-log-0x00-page-0x00-failed-emask-0x40} (Google-powered translation to English {url here;https://de-comp-hardware-laufwerke-festplatten-narkive-com.translate.goog/F8WstP5i/fix-frage-zu-sata-read-log-0x00-page-0x00-failed-emask-0x40?_x_tr_sl=bg&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp}).
.p
A user had the same issue as outlined in this post and were discussing the situation.
@@ -63,21 +63,21 @@ I'm leaving my original explanation, since some of it is still true.
The following is how I understand the issue, but I did not find definitive proof thats exactly what happens.\n
Take this section with a grain of salt.
-A harddrive can support [url https://en.wikipedia.org/wiki/Direct_memory_access dma transfers], normally the CPU would handle data transfer from the harddrive to the system memory (RAM), meaning it asks for a bit of data, waits, when the data comes, puts it in memory, then asks for next bit and so on.
+A harddrive can support {url dma transfers;https://en.wikipedia.org/wiki/Direct_memory_access}, normally the CPU would handle data transfer from the harddrive to the system memory (RAM), meaning it asks for a bit of data, waits, when the data comes, puts it in memory, then asks for next bit and so on.
With DMA, the CPU could ask the drive for everythng it wants (not a tiny bit), and then the DMA controller (DMAC) on the drive will handle the actual data transfer from the drive to the memory (when the transfer is done, the drive will tell the CPU).
The benefit is that the CPU can do other work while the transfer is going on, greatly improving efficiency, but the downside is that the harddrive has to support it (have a DMAC chip on it).
Normally it would be useful for the DMAC to keep logs in a special place on the drive.
-[~This is where the issue comes from: your harddrive supports DMA but does not support logs for it.
+{s This is where the issue comes from: your harddrive supports DMA but does not support logs for it.
However, the Linux kernel has no good way of knowing that, there is no "property" on the drive which tells us this.
-The only way is to try and read from that log: if it succeeds, then there is support, if it fails, then there isn't.~]
+The only way is to try and read from that log: if it succeeds, then there is support, if it fails, then there isn't.}
-[~But what does it mean to fail?
+{s But what does it mean to fail?
The simplest definition would be for the drive to return an error singal, but in our case, the drive would just not return anything, ignoring our request.
In that case, how would we know if the drive just doesn't know how to respond (meaning it doesn't support the logs) or if it's just very slow?
-Well, we can't, so we put a time limit, if it doesn't respond in 15 seconds, then it probably doesn't support it.~]
+Well, we can't, so we put a time limit, if it doesn't respond in 15 seconds, then it probably doesn't support it.}
-That's what the error is saying: [`qc`] is short for [url https://docs.kernel.org/driver-api/libata.html#origins-of-commands "queued command"], it's used to represent a (S)ATA command (hence the [`cmd`] at the end, telling us which command it's referring to).
+That's what the error is saying: {` qc} is short for {url "queued command";https://docs.kernel.org/driver-api/libata.html#origins-of-commands}, it's used to represent a (S)ATA command (hence the {` cmd} at the end, telling us which command it's referring to).
So, the kernel is telling us "The hard drive (ATA) command to read (DMA) logs timed out after 15 seconds" (it first says a command timed out, then it says which one).
By adding that kernel parameter, we're telling Linux that the drive doesn't support DMA logs, therefore the kernel doesn't need to do this "wait 15 seconds for response if support exists" routine.
diff --git a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du
index 0796818..602622f 100644
--- a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du
+++ b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du
@@ -1,17 +1,17 @@
-# Балове 2021
+'def title Балове 2021
+'def desc Кандидатстудентски балове за Компютърни Науки, Софтуерно Инженерство и Информатика във ФМИ през 2021
-'define expected-reading 3 min
-'define created 13 July 2023
-'define edited 14 July 2023
-[$pagenav]
+# {title}
-[*Тази страница е разширение на [url ./ "ФМИ и висшето образование в програмистката индустрия"].*]
+{pagenav 3 min;13 July 2023;14 July 2023}
+
+{i Тази страница е разширение на {url "ФМИ и висшето образование в програмистката индустрия";./}.}
Благодарение на електронната система за кандидатстване, имам минимални балове на трите класирания през 2021 за компютърни науки, софтуерно инженерство и информатика (без информационни системи, защото не исках да влизам там).
Понеже такава информация много не се разпространява, тук ще я споделя подробно.
Очевидна бележка: това са баловете за мъже, за жени са различни.
-Също в бележките под линия на оригиналната статия съм дал стойности и източници за [url ./#fn4 бройка кандидати през 2021].
+Също в бележките под линия на оригиналната статия съм дал стойности и източници за {url бройка кандидати през 2021;./#fn4}.
Напомням, че 2021 беше последната година с два изпита по математика: Математика I и Математика II.
Първият беше по-обикновен, със затворени и отворени въпроси, и задачи с решения.
@@ -19,9 +19,9 @@
Балът се формираше така:
.bulleted
-- 3 по оценката от Математика II [*или*] 2.5 по оценката от Математика I (което от двете носи по-голямо число)
+- 3 по оценката от Математика II {i или} 2.5 по оценката от Математика I (което от двете носи по-голямо число)
- +
-- ако си ходил на държавен зрелостен изпит по математика, оценката от него, [*иначе*] оценката по математика от дипломата
+- ако си ходил на държавен зрелостен изпит по математика, оценката от него, {i иначе} оценката по математика от дипломата
За някакво усещане за баловете, ще напиша минималната нужна оценка от изпитите, считайки оценката от ДЗИ или дипломата за 6,00.
Ако балът е под 13.5, то тогава със сигурност са приети студенти, които са имали по-малко от 6.00 на ДЗИ/диплома и са компенсирали с резултати на изпитите по математика (не може да кандидатстваш с оценка, по-ниска от 3.000).
@@ -30,7 +30,8 @@
## Първо класиране
-:table_4
+:table
+:4
|= Специалност - форма на обучение
|= Минимален бал
|= Мин. оценка по Математика I
@@ -67,14 +68,16 @@
|: 3.877
|: Информатика - платено редовно
-|: [*11.62*]
+|: {i 11.62}
|: 3.000
|: 3.000
+
## Второ класиране
-:table_4
+:table
+:4
|= Специалност - форма на обучение
|= Минимален бал
|= Мин. оценка по Математика I
@@ -91,7 +94,7 @@
|: 4.263
|: Информатика - редовно
-|: [*10.64*]
+|: {i 10.64}
|: 3.000
|: 3.000
@@ -116,9 +119,11 @@
|: -
+
## Трето класиране
-:table_4
+:table
+:4
|= Специалност - форма на обучение
|= Минимален бал
|= Мин. оценка по Математика I
@@ -135,7 +140,7 @@
|: 4.406
|: Информатика - редовно
-|: [*12.00*]
+|: {i 12.00}
|: 3.000
|: 3.000
diff --git a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du
index ec2f9b8..75fbcbf 100644
--- a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du
+++ b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du
@@ -1,46 +1,46 @@
-# ФМИ и висшето образование в програмистката индустрия
+'def title ФМИ и висшето образование в програмистката индустрия
+'def desc Сравнение на различни български университети с ФМИ, разглеждане на предметите във ФМИ и общо мнение за факултета
-'define expected-reading 39 min
-'define created 12 July 2023
-'define edited 14 July 2023
-[$pagenav]
+# {title}
+
+{pagenav 39 min;12 July 2023;14 July 2023}
:contents
:numbered
-1. [url #section-2 Кой съм аз]
-2. [url #section-3 Университетите в България (София)]
+1. {uhref Кой съм аз}
+2. {uhref Университетите в България (София)}
.numbered
- 1. [url #section-4 УниБит]
- 2. [url #section-5 НБУ]
- 3. [url #section-6 Технически университет]
+ 1. {uhref УниБит}
+ 2. {uhref НБУ}
+ 3. {uhref Технически университет}
-4. [url #section-7 ФМИ]
+4. {uhref ФМИ}
:numbered
- 1. [url #section-8 Специалности]
- 2. [url #section-9 Влизане]
- 3. [url #section-10 Следване и оцеляване]
+ 1. {uhref Специалности}
+ 2. {uhref Влизане}
+ 3. {uhref Следване и оцеляване}
.numbered
- 1. [url #section-11 Оценяване, влачене и повтаряне]
- 2. [url #section-12 Седмична заетост]
- 3. [url #section-13 Преподаватели]
- 4. [url #section-14 Избираеми дисциплини и работа]
+ 1. {uhref Оценяване, влачене и повтаряне}
+ 2. {uhref Седмична заетост}
+ 3. {uhref Преподаватели}
+ 4. {uhref Избираеми дисциплини и работа}
- 4. [url #-2 Какво се учи в КН2]
+ 4. {uhref Какво се учи в КН2}
:numbered
- 1. [url #section-15 Училищната математика\nсрещу университетската математика]
- 2. [url #section-16 Първи курс: М-то във ФМИ означава МатеМатика]
+ 1. {uhref Училищната математика\nсрещу университетската математика}
+ 2. {uhref Първи курс: М-то във ФМИ означава МатеМатика}
.numbered
- 1. [url #section-17 Зимен семестър]
- 2. [url #section-18 Летен семестър]
+ 1. {uhref Зимен семестър}
+ 2. {uhref Летен семестър}
- 3. [url #section-19 Втори курс: И-то във ФМИ означава математИка]
+ 3. {uhref Втори курс: И-то във ФМИ означава математИка}
.numbered
- 1. [url #section-20 Зимен семестър]
- 2. [url #section-21 Летен семестър]
+ 1. {uhref Зимен семестър}
+ 2. {uhref Летен семестър}
-5. [url #section-22 Има ли смисъл от следване във фми? ДА!]
+5. {uhref Има ли смисъл от следване във фми? ДА!}
@@ -49,15 +49,15 @@
И цялата тази дискусия се намира в постове от преди 5-10 години...
Аз вече съм следвал 2 години в университет, плюс това имам сериозен опит от преди това.
-Макар и този блогпост да е главно за [url https://www.fmi.uni-sofia.bg/ Факултета по Математика и Информатика] към [url https://www.uni-sofia.bg/index.php Софийски Университет], по-общата ми цел е да споделя всичко , което знам свързано с образованието в индустрията.
+Макар и този блогпост да е главно за {url Факултета по Математика и Информатика;https://www.fmi.uni-sofia.bg/} към {url Софийски Университет;https://www.uni-sofia.bg/index.php}, по-общата ми цел е да споделя всичко , което знам свързано с образованието в индустрията.
-Бърза бележка: всичко казано [=важи за моя випуск=], с времето нещата се изменят и може повечето информация тук да бъде [=остаряла=].
-Допълнително, [url ./balove-2021.html тук] имам изкарани баловете във ФМИ (на СУ) за 2021 година.
+Бърза бележка: всичко казано {b важи за моя випуск}, с времето нещата се изменят и може повечето информация тук да бъде {b остаряла}.
+Допълнително, {url тук;./balove-2021.html} имам изкарани баловете във ФМИ (на СУ) за 2021 година.
## Кой съм аз
Този блогпост няма да бъде напълно неутрален и ще включва моето мнение, затова е добре да знаеш от къде идва моята гледна точка.
-Завършил съм [url https://www.feg.bg/ 9 Френска езикова гимназия], обаче едновременно от 10 до 12 клас участвах интензивно в националната програма [url https://it-kariera.mon.bg/e-learning/ ИТ-кариера].
+Завършил съм {url 9 Френска езикова гимназия;https://www.feg.bg/}, обаче едновременно от 10 до 12 клас участвах интензивно в националната програма {url ИТ-кариера;https://it-kariera.mon.bg/e-learning/}.
Накратко, в тази програма изучавах практически неща, главните няколко типове програмирания, и към края се занимавах с разработване на софтуер на сравнително индустриално ниво (или поне най-близкото до това).
От цялата програма бях единствения от център София с пълно отличие.
@@ -73,7 +73,7 @@
## Университетите в България (София)
Сега ще обсъдим какви са алтернативите на ФМИ, и защо те не са толкова добри.
-В София има четири (смислени) университета, които предлагат някаква форма на софтуерно образование: [url https://www.uni-sofia.bg/ Софийски университет], [url https://nbu.bg/ Нов Български Университет], [url https://www.tu-sofia.bg/ Техническия Университет] и [url https://www.unibit.bg/ Университет по Библеотекознание и Информационни технологии].
+В София има четири (смислени) университета, които предлагат някаква форма на софтуерно образование: {url Софийски университет;https://www.uni-sofia.bg/}, {url Нов Български Университет;https://nbu.bg/}, {url Техническия Университет;https://www.tu-sofia.bg/} и {url Университет по Библеотекознание и Информационни технологии;https://www.unibit.bg/}.
Този пост ще бъде посветен на първата от тези опции, но все пак покрай приятели и колеги имам добра представа за другите опции.
### УниБит
@@ -103,8 +103,8 @@
### Технически университет
-Не съм чувал много, но техническият университет се занимава повече с инженерство, така че [url https://tu-sofia.bg/uplan/%D0%A4%D0%9A%D0%A1%D0%A2/%D0%91%D0%B0%D0%BA%D0%B0%D0%BB%D0%B0%D0%B2%D1%8A%D1%80/FKSU_UPlan_BCSCe_zadochno.pdf се учат не толкова свързани предмети], като физика, проектиране и електротехника.
-[url https://old.reddit.com/r/bulgaria/comments/tqy9l4/%D1%84%D0%BC%D0%B8_%D0%B8%D0%BB%D0%B8_%D1%82%D1%83/ Доколкото виждам онлайн, мненията не са позитивни]:
+Не съм чувал много, но техническият университет се занимава повече с инженерство, така че {url се учат не толкова свързани предмети;https://tu-sofia.bg/uplan/%D0%A4%D0%9A%D0%A1%D0%A2/%D0%91%D0%B0%D0%BA%D0%B0%D0%BB%D0%B0%D0%B2%D1%8A%D1%80/FKSU_UPlan_BCSCe_zadochno.pdf}, като физика, проектиране и електротехника.
+{url Доколкото виждам онлайн, мненията не са позитивни;https://old.reddit.com/r/bulgaria/comments/tqy9l4/%D1%84%D0%BC%D0%B8_%D0%B8%D0%BB%D0%B8_%D1%82%D1%83/}:
.quote
За IT ТУ е абсолютна загуба на време - редовно ми идват стажанти от там. Ако не са се занимавали с програмиране от преди това, почваме от 0
@@ -126,10 +126,10 @@
Във ФМИ много от предметите са математики и програмиранията се говори, че не са много добре.
Онлайн има стотици часове материали и курсове, повечето от които са безплатни, на всяка тема свързана с програмиране.
-Допълнително имаш [url https://www.telerikacademy.com/ Telerik Academy] и [url https://softuni.bg/ SoftUni] (само искам да напомня, че [=СофтУни не е университет=], макар и така да се казват) - две места които предлагат разнообразни програмистки и чисто практически курсове (и също дават сертификати).
+Допълнително имаш {url Telerik Academy;https://www.telerikacademy.com/} и {url SoftUni;https://softuni.bg/} (само искам да напомня, че {b СофтУни не е университет}, макар и така да се казват) - две места които предлагат разнообразни програмистки и чисто практически курсове (и също дават сертификати).
А и повечето програмисти нямат висше и са самоуки, тоест този път не е изобщо странен, даже е най-често следвания.
-Финалното ми мнение се намира [url #section-19 най-долу], но един такова решение трябва да се вземе с възможно най-много информация.
+Финалното ми мнение се намира {url най-долу;#section-19}, но един такова решение трябва да се вземе с възможно най-много информация.
### Специалности
@@ -137,18 +137,16 @@
Технически всяка се занимава с различни неща, но на практика всички влезли искат да са програмисти.
От тях, най-желани са компютърни науки и софтуерно инженерство (тези ще наричам "хубавите" специалности).
-В информатика се влизаше много лесно, там балът беше [url ./balove-2021.html безнадеждно нисък], обаче следването е най-трудно от всички останали дисциплини.
-Късането е брутално, особено първи курс: по Алгебра 1 от към 200 човека (това включваше и минали години май) само един човек беше [*допуснат*] до изпит (ама си го мина де).
+В информатика се влизаше много лесно, там балът беше {url безнадеждно нисък;./balove-2021.html}, обаче следването е най-трудно от всички останали дисциплини.
+Късането е брутално, особено първи курс: по Алгебра 1 от към 200 човека (това включваше и минали години май) само един човек беше {i допуснат} до изпит (ама си го мина де).
По дискретни структури бяха повече, цели 10тима човека.
-Общо от 1ви курс преминаха успешно 20-30 човека във 2ри курс (за да минеш не е нужно всички изпити да си минал, ама детайли [url #section-10 по-късно]).
+Общо от 1ви курс преминаха успешно 20-30 човека във 2ри курс (за да минеш не е нужно всички изпити да си минал, ама детайли {url по-късно;#section-10}).
Има няколко причини за това:
.bulleted
- от една страна бала като е най-нисък, хората с най-ниски умения по математика се намират там, така че успехите ще са най-ниски,
- от друга страна има и преподаватели които са прекомерно неадекватни като изпитване и преподаване.
-'footnote inf-sistemi Признавам, за тази информация използвах [url https://forums.bgdev.org/index.php?showtopic=34217&st=0&#entry255351 това мнение от форум], никой не обсъжда ИС.
-
-Информационни системи от своя страна сякаш се занимава повече с бази данни и проектиране на информационни системи[$inf-sistemi], не толкова чисто програмиране и нещата около него.
+Информационни системи от своя страна сякаш се занимава повече с бази данни и проектиране на информационни системи{fn Признавам, за тази информация използвах {url това мнение от форум;https://forums.bgdev.org/index.php?showtopic=34217&st=0&#entry255351}, никой не обсъжда ИС.}, не толкова чисто програмиране и нещата около него.
Признавам, че не съм чувал много за тях, ама балът не изглежда да е много висок (мисля че е по-висок от информатика) и мисля, че следването е най-лесно от 4те специалности.
Сега, компютърни науки и софтуерно инженерство.
@@ -164,30 +162,28 @@
Само по Алгебра 1 и Геометрия минават към 20-30 човека от първия път, по останалите си минават повечето.
Макар че сравнително непланирано им сложиха доста взискателни преподаватели през 2ри курс, не знам дали те ще останат в бъдещи години, така че разликата между КН1 и КН2 може да се стопи.
-'footnote minali-1-kurs Тази статистика е взета директно от таблици с оценки на редовни студенти на [url https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=228877 първи курс по Дискретни структури] и [url https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=283034 втори курс по Дизайн и Анализ на Алгоритми]. Тези таблици са правени от лектора по списъци от СУСИ (онлайн системата за студенти). Ще спомена по-късно, но дългите факултетни номера, в които има и букви, са на студентите, влезли през 2021, докато кратките пет-цифрени са на студенти от минали години, които повтарят.
-
КН2 вече е доста по-трудно, тук ежегодно по Диференциално и интегрално смятане минават 20-30 човека, а по Дискретни структури минават по 10тина.
Напомням, че аз влязох тук.
-Приблизително 44%[$minali-1-kurs] от редовните студенти (които не повтарят) успешно минаха (минахме ;)) към втори курс.
+Приблизително 44%{fn Тази статистика е взета директно от таблици с оценки на редовни студенти на {url първи курс по Дискретни структури;https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=228877} и {url втори курс по Дизайн и Анализ на Алгоритми;https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=283034}. Тези таблици са правени от лектора по списъци от СУСИ (онлайн системата за студенти). Ще спомена по-късно, но дългите факултетни номера, в които има и букви, са на студентите, влезли през 2021, докато кратките пет-цифрени са на студенти от минали години, които повтарят.} от редовните студенти (които не повтарят) успешно минаха (минахме ;)) към втори курс.
Иначе имам впечатлението, че най-умните и умелите хора измежду компютърни науки и софтуерно инженерство се намират тук, макар че това зависи от випуска: няма гаранция, че един много умен кандидат-студент ще реши да се запише за КН (и ще попадне в КН2).
Като обобщение, това са дисциплините подредени от най-трудна за минаване към най-лесна:
:ordered
-1. [=Информатика=]: много трудно, не по много основателни причини, макар че като цяло малцинството което успява да завърши са на високо ниво.
+1. {b Информатика}: много трудно, не по много основателни причини, макар че като цяло малцинството което успява да завърши са на високо ниво.
Не препоръчвам, ако не си много издържлив и КН и СИ не са се получили.
-2. [=Компютърни науки, 2ри поток=]: трудно, но като цяло е сравнително основателно (пак на моменти е малко нечестно, но не толкова колкото при информатика), нивото просто е високо.
+2. {b Компютърни науки, 2ри поток}: трудно, но като цяло е сравнително основателно (пак на моменти е малко нечестно, но не толкова колкото при информатика), нивото просто е високо.
Поне от моя випуск, повечето от най-добрите се намират тук.
Ако си представим, че има някакво перфектно ниво на обучение, където не е твърде лесно, но и не е твърде трудно, бих казал че КН2 се намира малко над това ниво.
-3. [=Компютърни науки, 1ви поток=]: малко по-лесно от КН2, но с малко понижаване на качеството.
+3. {b Компютърни науки, 1ви поток}: малко по-лесно от КН2, но с малко понижаване на качеството.
Има добро количество материал, което в КН2 ти е набито в главата, докато при КН1 си го забравил след лятната ваканция (не че това не важи в обратната посока, но в КН2 ни вкарват повече неща в умовете).
В сравнение с перфектното ниво, КН1 е малко под него.
Обаче трябва да се има в предвид, че 2ри курс сложиха доста взискателни преподаватели.
Ако това се запази, разликата между двата потока може да изчезне.
-4. [=Софтуерно инженерство=]: забележимо по-лесно от компютърни науки, повечето хора по повечето дисциплини минават без твърде много проблеми.
+4. {b Софтуерно инженерство}: забележимо по-лесно от компютърни науки, повечето хора по повечето дисциплини минават без твърде много проблеми.
Ама нивото също спада забележително, макар и бала да е най-висок.
Както споменах, при компютърни науки е по-добре, ама нивото на СИ пак е сравнително ок.
-5. [=Информационни системи=]: нисичък бал и сравнително лесно, но не ми изглежда да е супер развиващо за програмисти.
+5. {b Информационни системи}: нисичък бал и сравнително лесно, но не ми изглежда да е супер развиващо за програмисти.
Не бих препоръчал, освен ако алтернативата не е информатика.
@@ -200,35 +196,23 @@
Сега главният определящ изпит е просто "Математика" и включва сложни въпроси като "кое от следните числа е най-голямо" и "намерете броя решения на уравнението".
Разбира се, с това си идват свои трудности, и най-малката грешка може да постави 10-20 човека над тебе като успех, но в края на деня не се изисква толкова много тренинг както при моите изпити.
-'footnote mat-i-ii Макар че това не е много добра причина за смяна на изпитването, понеже схемата с два такива изпита (единия стандартен и другия с малко задачи, но с пълни решения) си е държала още от времето на комунизма. Моето предположение за тази промяна, е че новата система е влошила качеството на обучение твърде много и искат минималните оценки за влизане се повишават обратно към околността на 6ца, но това вече са мои си конспирации.
-
-'footnote 2021-kandidati Такива статистики много не се намират публично и линковете не са сложени на достъпно място, но успях да изровя директните линкове към разпределението по зали за [url https://www.uni-sofia.bg/index.php/bul/content/download/249347/1644279/version/1/file/2021-04-24_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0+II.pdf първа изпитна сесия по Математика II], [url https://www.uni-sofia.bg/index.php/bul/content/download/250518/1651896/version/1/file/2021-05-23_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0+I.pdf първата изпитна сесия по Математика I] и [url https://www.uni-sofia.bg/index.php/bul/content/download/250730/1653146/version/1/file/2021-05-30_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0+II.pdf втората изпитна сесия по Математика II] през 2021 година (ако някой от тях спре да работи, архивирани са на [url https://web.archive.org/ archive.org]). До всяка зала пише колко човека са разпределени за там, така че общата бройка е една проста сума. Най-много хора са се явили на първата сесися по Математика II: 593, на Математика I са 514 и на втората сесия по Математика II са 568.
-
-Моята генерация беше последната по старата програма на обучение[$mat-i-ii], така че при кандидатстване се вземаше една от оценките на изпитите Математика I или Математика II (като втория изпит допринася повече към бала).
+Моята генерация беше последната по старата програма на обучение{fn Макар че това не е много добра причина за смяна на изпитването, понеже схемата с два такива изпита (единия стандартен и другия с малко задачи, но с пълни решения) си е държала още от времето на комунизма. Моето предположение за тази промяна, е че новата система е влошила качеството на обучение твърде много и искат минималните оценки за влизане се повишават обратно към околността на 6ца, но това вече са мои си конспирации.}, така че при кандидатстване се вземаше една от оценките на изпитите Математика I или Математика II (като втория изпит допринася повече към бала).
Математика I беше сравнително стандартен, напомнящ на модерната "Математика" или матурата, обаче Математика II беше съвсем друго животно: там имаш 8 задачи, всяка с отворен отговор и изисквано решение.
-Този изпит беше трудният и до голяма степен определящият, от максимум 593[$2021-kandidati] човека се рееха слухове че само 20тина са имали 6,00.
-
-'footnote 2021-mesta Този документ вече е лесно достъпен в [url https://www.uni-sofia.bg/index.php/bul/content/download/259611/1706172/version/1/file/%D0%9C%D0%B5%D1%81%D1%82%D0%B0+%D0%94%D0%9F.pdf сайта на СУ]. Също говоря за нормалните места по държавна субсидия: без платено обучение и българи, живеещи в чужбина.
-
-'footnote visoki-iziskvaniq Доколкото съм чувал, тази схема е била валидна до към 2014, поне за специалности като компютърни науки и софтуерно инженерство. Сякаш малко след това баловете на всичко започват яко да падат, ама такива статистики вече хептен ги няма публично. Единствената така информация имат кандидат-студенти, и то за своята година в която влизат, и не се познавам с достатъчно хора, за да разпитвам.
+Този изпит беше трудният и до голяма степен определящият, от максимум 593{fn Такива статистики много не се намират публично и линковете не са сложени на достъпно място, но успях да изровя директните линкове към разпределението по зали за {url първа изпитна сесия по Математика II;https://www.uni-sofia.bg/index.php/bul/content/download/249347/1644279/version/1/file/2021-04-24_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0+II.pdf}, {url първата изпитна сесия по Математика I;https://www.uni-sofia.bg/index.php/bul/content/download/250518/1651896/version/1/file/2021-05-23_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0+I.pdf} и {url втората изпитна сесия по Математика II;https://www.uni-sofia.bg/index.php/bul/content/download/250730/1653146/version/1/file/2021-05-30_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0+II.pdf} през 2021 година (ако някой от тях спре да работи, архивирани са на {url archive.org;https://web.archive.org/}). До всяка зала пише колко човека са разпределени за там, така че общата бройка е една проста сума. Най-много хора са се явили на първата сесися по Математика II: 593, на Математика I са 514 и на втората сесия по Математика II са 568.} човека се рееха слухове че само 20тина са имали 6,00.
-Въпреки това, влизането във ФМИ беше лесно, общо имаше 525[$2021-mesta] места, предостатъчно, имайки предвид, че не всички явили се на тези изпити, кандидатстваха в компютърна специалност (оценката важи за физическия и стопанския факултет).
+Въпреки това, влизането във ФМИ беше лесно, общо имаше 525{fn Този документ вече е лесно достъпен в {url сайта на СУ;https://www.uni-sofia.bg/index.php/bul/content/download/259611/1706172/version/1/file/%D0%9C%D0%B5%D1%81%D1%82%D0%B0+%D0%94%D0%9F.pdf}. Също говоря за нормалните места по държавна субсидия: без платено обучение и българи, живеещи в чужбина.} места, предостатъчно, имайки предвид, че не всички явили се на тези изпити, кандидатстваха в компютърна специалност (оценката важи за физическия и стопанския факултет).
Вече за конкретни специалности беше малко по-трудно, 300 от тези места бяха в хубавите компютърни специалности, така че конкуренцията беше горе-долу двама човека за едно място.
Също е добре да спомена, че баловете бяха супер ниски, в компютърни науки влязох с 4.70 (на Математика II) на първо класиране, на второ можеше и с 4.30 да вляза.
-Конкретни стойности за баловете от тази година съм изкарал [url ./balove-2021.html тук].
-В Софтуерно инженерство бяха малко по-високи изискванията (а там бяха най-високи от компютърните специалности), ама пак, далеч от времето, когато с 5.40 е можело и да не влезеш[$visoki-iziskvaniq].
+Конкретни стойности за баловете от тази година съм изкарал {url тук;./balove-2021.html}.
+В Софтуерно инженерство бяха малко по-високи изискванията (а там бяха най-високи от компютърните специалности), ама пак, далеч от времето, когато с 5.40 е можело и да не влезеш{fn Доколкото съм чувал, тази схема е била валидна до към 2014, поне за специалности като компютърни науки и софтуерно инженерство. Сякаш малко след това баловете на всичко започват яко да падат, ама такива статистики вече хептен ги няма публично. Единствената така информация имат кандидат-студенти, и то за своята година в която влизат, и не се познавам с достатъчно хора, за да разпитвам.}.
-'footnote 2022-kandidati Както за 2021, пак трябваше да се ровя, но намерих разпределението по зали за [url https://www.uni-sofia.bg/index.php/bul/content/download/266692/1750342/version/1/file/2022-04-03_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0.pdf единствената изпитна сесия по Математика] през 2022 (също архивирано в [url https://web.archive.org/ archive.org]).
-
-'footnote 2023-kandidati Както за 2021, пак имаше ровене, но намерих разпределението по зали за [url https://www.uni-sofia.bg/index.php/bul/content/download/285793/1865079/version/1/file/2023-04-02_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0%E2%80%93%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5%D0%BD_%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB.pdf първата изпитна сесия по Математика] и [url https://www.uni-sofia.bg/index.php/bul/content/download/290157/1891849/version/1/file/2023-06-11_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0.pdf втората изпитна сесия по математика] (както винаги, налични в [url https://web.archive.org/ archive.org]). На първата са се явили 979 и 875 на втората.
-
-С новия изпит вече конкуренцията е малко по-висока, все пак са се явили 969[$2022-kandidati] ученици на Математика през 2022 и максимум 979[$2023-kandidati] през 2023.
+С новия изпит вече конкуренцията е малко по-висока, все пак са се явили 969{fn Както за 2021, пак трябваше да се ровя, но намерих разпределението по зали за {url единствената изпитна сесия по Математика;https://www.uni-sofia.bg/index.php/bul/content/download/266692/1750342/version/1/file/2022-04-03_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0.pdf} през 2022 (също архивирано в {url archive.org;https://web.archive.org/}).} ученици на Математика през 2022 и максимум 979{fn Както за 2021, пак имаше ровене, но намерих разпределението по зали за {url първата изпитна сесия по Математика;https://www.uni-sofia.bg/index.php/bul/content/download/285793/1865079/version/1/file/2023-04-02_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0%E2%80%93%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5%D0%BD_%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB.pdf} и {url втората изпитна сесия по математика;https://www.uni-sofia.bg/index.php/bul/content/download/290157/1891849/version/1/file/2023-06-11_09-00_%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0.pdf} (както винаги, налични в {url archive.org;https://web.archive.org/}). На първата са се явили 979 и 875 на втората.} през 2023.
Местата са същия брой, така че излиза към примерно трима човека за едно място и ако примерно имаш 3ка или 4ка може и да не влезеш във ФМИ.
-Обаче, [=най-важното: материалът във ФМИ не се е изменил!=]
+Обаче, {b най-важното: материалът във ФМИ не се е изменил!}
Макар и изпитът да е значително по-лесен, трудността на материала не се е снижила (или поне толкова, колкото изпита) и в същото време математиката се изучава доста.
Тоест, един човек, влязъл с най-ниския бал на Математика ще е далеч по-неподготвен за ФМИ от човек с минимален бал на Математика II.
-Затова [=препоръчвам всеки кандидат-студент да може да реши някоя Математика II за към 4-4.50!=]
+Затова {b препоръчвам всеки кандидат-студент да може да реши някоя Математика II за към 4-4.50!}
Това са горе-долу 5-6 от 8те задачи.
Иначе ако не можеш редовно да учиш математика и не можеш да се справиш с такива задачи (които са по-прости като характер в сравнение с това, което учим в университета), следването ти ще бъде твърде трудно според мен.
@@ -253,12 +237,10 @@
Оценката се формира по различни начини при различните предмети, но най-често контролните и домашните през семестъра носят 40-50% и през сесията си изкарваш останалата част от оценката.
Също понякога, ако си се справил достатъчно добре на контролните през семестъра, може да бъдеш освободен от изпит-задачи (не е нужно да ходиш и като оценка на него ти се пише средно аритметично от контролните).
-Обаче почти винаги [=ако изкараш двойка на някой от изпитите през сесията, цялата ти оценка за предмета става двойка!=]
-
-'footnote september Разговорно на поправителната сесия им викаме септември, макар и само един-два дена от нея да са в този месец. Причината е, че просто до преди няколко години наистина е била през септември, но са я изместили назад. Защо са я изместили, не знам.
+Обаче почти винаги {b ако изкараш двойка на някой от изпитите през сесията, цялата ти оценка за предмета става двойка!}
Когато не си минал един предмет, ти го "влачиш".
-За всеки предмет имаш две дати през академичната година, през които може да го вземеш: редовната сесията след семестър (тоест когато по принцип се изпитват хора по този предмет) и поправителната сесия, която се случва във втората половина от август[$september].
+За всеки предмет имаш две дати през академичната година, през които може да го вземеш: редовната сесията след семестър (тоест когато по принцип се изпитват хора по този предмет) и поправителната сесия, която се случва във втората половина от август{fn Разговорно на поправителната сесия им викаме септември, макар и само един-два дена от нея да са в този месец. Причината е, че просто до преди няколко години наистина е била през септември, но са я изместили назад. Защо са я изместили, не знам.}.
По принцип имаш и ликвидационна сесия, ама идеята е, ако два изпита през поправителната сесия ти се препокриват, през поправителната да отидеш на единия и на ликвидационната да може да отидеш на другия (трябва да подадеш документ, че това си направил, не можеш да отложиш изпити ей така).
Можеш да преминеш към следващия курс без проблеми ако влачиш максимум 3 предмета от годината.
@@ -282,7 +264,7 @@
Количеството подготовка за едно контролно зависи от човек на човек, но ако нищо не си учил, бих казал че е поне една-две интензивни седмици за сериозните предмети са достатъчни.
За домашните е по-малко, защото по принцип те са върху неща, изучавани на упражнения, така че ако си си водел записки (или споделящи колеги са водели) ще знаеш как да решиш всички задачи (разбира се, има изключения).
-Това обаче е [=само за контролни-задачи по някои предмети=], все пак имаш теория и имаш задачи за които ти трябва теория, и тя вече не може да се научи толкова бързо.
+Това обаче е {b само за контролни-задачи по някои предмети}, все пак имаш теория и имаш задачи за които ти трябва теория, и тя вече не може да се научи толкова бързо.
Нещо много хубаво е, че никой не следи за присъствие на занятия и не се пишат отсъствия както в училище.
Разбира се, това не означава, че не е нужно да се ходи на всички занятия, напротив, но ако искаш винаги може да пропуснеш нещо.
@@ -305,16 +287,16 @@
Обаче, си задължен и да ходиш на избираеми дисциплини: имаш минимален брой избираеми за всеки семестър, минимален общ брой за всичките години и минимален брой ECTS кредити за всичките години.
За разлика от училище, имаш доста голям избор и много от тях са интересни и полезни.
-Обаче, [=не записвай избираеми през първи курс!=]
-Скоро ще обсъдим предметите, обаче [=първи курс е най-труден и изисква цялото ти работно време!=]
-Това трябва да навежда на мисълта, че [=не трябва да работиш по време на първи курс=], освен ако не ти се налага или не си от най-умните хора в специалността.
+Обаче, {b не записвай избираеми през първи курс!}
+Скоро ще обсъдим предметите, обаче {b първи курс е най-труден и изисква цялото ти работно време!}
+Това трябва да навежда на мисълта, че {b не трябва да работиш по време на първи курс}, освен ако не ти се налага или не си от най-умните хора в специалността.
Материалът е нещо напълно ново, не само като изучавани неща, ами и като концепции и модел на учене.
-Ама каквото и да си говорим, [=най-доброто обучение се намира в избираемите дисциплини!=]
+Ама каквото и да си говорим, {b най-доброто обучение се намира в избираемите дисциплини!}
Не е задължително да си доцент или професор, за да направиш избираема, и може да я направиш както си искаш.
Има много такива, които се водят от бивши студенти на ФМИ, които сега работят в големи компании, и предоставят супер практично и готино обучение.
-За някои неща даже не можеш да намериш в България курсове, като [url https://intranet.fmi.uni-sofia.bg/index.php/s/uGI4XDReO3WoUok Реализация на езици за програмиране], където се разглежда как се правят компилатори или [url https://intranet.fmi.uni-sofia.bg/index.php/s/v2v4WlP2GdDbWtb Употреба и скриптиране на Vim], където подробно поглежда един от най-добрите текстови редактори някога създавани.
+За някои неща даже не можеш да намериш в България курсове, като {url Реализация на езици за програмиране;https://intranet.fmi.uni-sofia.bg/index.php/s/uGI4XDReO3WoUok}, където се разглежда как се правят компилатори или {url Употреба и скриптиране на Vim;https://intranet.fmi.uni-sofia.bg/index.php/s/v2v4WlP2GdDbWtb}, където подробно поглежда един от най-добрите текстови редактори някога създавани.
### Какво се учи в КН2
@@ -336,17 +318,13 @@
Твърденията са неща, които казваме че са верни за дадена конструкция, тоест за нещо, което си измислим (и което не противоречи на аксиомите).
Конструкция е ключова дума, понеже сътворяваме с въображение някакъв обект, нещо с някакви свойства и после доказваме, чисто формално и прецизно със стриктно определени уреди, че дадения обект прави това, което искаме.
-'footnote def-set Формално няма дефиниция на множество, понеже става малко бездънно: какво е множество, еми колекция от елементи, какво е колекция от елементи, еми съвкупност от елементи, какво е съвкупност, еми множество от елементи. Формално казваме, че множество е първично понятие, тоест че няма дефиниция и се надяваме, че читателя схваща за какво се говори.
-
-'footnote axiom-of-choice В интерес на истината, това със сигурност е вярно само когато приемаме [url https://en.wikipedia.org/wiki/Axiom_of_choice аксиомата за избора], ако не я приемем, тогава доооста неща стават супер неинтуитивни и изглеждат грешни, обаче чисто формално и математически са верни.
-
Трудно ми е да дам лесен пример, понеже нищо в училище не може и да се сравнява, но нека да пробваме следното: нека да разгледаме множества.
-Множество е просто някаква колекция от елементи[$def-set], представи си кутия с някакви предмети в нея.
+Множество е просто някаква колекция от елементи{fn Формално няма дефиниция на множество, понеже става малко бездънно: какво е множество, еми колекция от елементи, какво е колекция от елементи, еми съвкупност от елементи, какво е съвкупност, еми множество от елементи. Формално казваме, че множество е първично понятие, тоест че няма дефиниция и се надяваме, че читателя схваща за какво се говори.}, представи си кутия с някакви предмети в нея.
Аз твърдя, че едно празно множество е елемент на друго празно множество, тоест че една празната кутия се съдържа в друга празна кутия.
-Това е очевидно грешно[$axiom-of-choice], нашето доказателство е, че щом кутията е празна, то по дефиниция няма елементи, следователно няма как да има друга кутия в нея.
+Това е очевидно грешно{fn В интерес на истината, това със сигурност е вярно само когато приемаме {url аксиомата за избора;https://en.wikipedia.org/wiki/Axiom_of_choice}, ако не я приемем, тогава доооста неща стават супер неинтуитивни и изглеждат грешни, обаче чисто формално и математически са верни.}, нашето доказателство е, че щом кутията е празна, то по дефиниция няма елементи, следователно няма как да има друга кутия в нея.
Ето: конструкция, твърдение и доказателство, доста елементарно и очевидно, но все пак се опитвам да не навлизам в детайли, а и в математиката има такива резултати, които не са хич очевидни.
-Също, доказателството, че нещо не е вярно може би изглежда безполезно, но някои от [url https://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem най-големите теореми на математиката са формулиране така].
+Също, доказателството, че нещо не е вярно може би изглежда безполезно, но някои от {url най-големите теореми на математиката са формулиране така;https://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem}.
Сега вече ще обсъдим конкретно изучаваните предмети в детайл.
@@ -357,7 +335,7 @@
##### Зимен семестър
-[=Алгебра 1=]: пълното име е линейна алгебра.
+{b Алгебра 1}: пълното име е линейна алгебра.
Занимава се главно с линейни уравнения (ax + by + ... + mz = k), обаче интересното идва като изследваме операции върху тях и ги навържем в пространства.
Много фундаментален предмет, използват се поне части от него в много клони на математиката и инженерството (защото много неща могат да се моделират с нея).
Има употреби в machine learning, в компютърната графика, в алгоритми за препоръки (търсачки примерно), обработка на изображения и много други.
@@ -365,7 +343,7 @@
Има по една малка задача всяка седмица, но не са трудни, изисква постоянство.
Предметът се минава без твърде много трудности, лекционните записки са много прецизно написани и упражненията са супер.
-[=Диференциално и интегрално смятане 1=]: с други думи, реален анализ.
+{b Диференциално и интегрално смятане 1}: с други думи, реален анализ.
Главно разглеждаме свойства и операции върху функции и редици числа.
В училище учим производни; глаголът да правиш производни разговорно може да се нарече "производиране", обаче терминът е диференциране.
Интегрирането е обраното действие на диференцирането, тоест намирането на функция, имайки само нейната производна.
@@ -376,7 +354,7 @@
Главната цедка е теорията, на която имаш теоретични задачи, при които дори за 3ка ще трябва да приложиш малко усет към предмета.
Като цяло просто изискванията са високи, иначе екипа са готини и бих казал, че оценяването е честно.
-[=Дискретни структури=]: този предмет е малко смесица от три предмета - булева алгебра, увод в теория на множествата, комбинаторика и теория на графите.
+{b Дискретни структури}: този предмет е малко смесица от три предмета - булева алгебра, увод в теория на множествата, комбинаторика и теория на графите.
От всичките математики, това е може би най-важната за програмиране.
В определен смисъл на думата, ДИС се занимава с безкрайно много и безкрайно малки елементи: на една функция може да и подадеш числото 1, но и 1.1, и 1.11 и так. нат., без проблем.
Обаче ДСТР разглежда дискретни обекти, тоест някакъв краен брой конкретни неща.
@@ -397,7 +375,7 @@
Ама трябва да предупредя, че не получаваш точки за половинчати решения, като цяло или си решил задачата коректно или не.
Бих казал че при този предмет се появяват нечестности или прекомерно високи изисквания на моменти, но се минава.
-[=Увод в програмирането=], неговото значение трябва да е очевидно.
+{b Увод в програмирането}, неговото значение трябва да е очевидно.
Изучава се C++, макар и някои неща да не са направени по най-добрите начини.
Налага се да знаеш и ползваш точно нещата, които ти се преподават и нищо друго.
Не бих казал, че е лошо направен, има някакво основание за тази методика, обаче някои неща се разглеждат твърде формално и програмирането не се изучава като динамичен предмет, в който може да решиш проблеми по много начини, а като задача по математика, където се изисква определено решение.
@@ -410,9 +388,9 @@
##### Летен семестър
-[=Диференциално и интегрално смятане 2=]: директно продължение на ДИС1.
+{b Диференциално и интегрално смятане 2}: директно продължение на ДИС1.
-[=Геометрия=]: истинското име на този предмет е аналитична геометрия и няма нищо общо с училищната евклидова геометрия.
+{b Геометрия}: истинското име на този предмет е аналитична геометрия и няма нищо общо с училищната евклидова геометрия.
Разглеждаме пространствата и геометричните обекти като по-абстрактни неща, или по-конкретно, разглеждаме повече числата и зависимостите между конкретни обекти.
Централно в компютърната графика и всичко около нея (обработка на изображения, 3D моделиране, ...).
@@ -420,18 +398,18 @@
Упражненията са супер, има и много добри записки по тях.
Минава се без твърде много проблеми.
-[=Езици, автомати и изчислимост=]: вторият най-важен предмет от математиките, на английски се казва Theoretical Computer Science.
+{b Езици, автомати и изчислимост}: вторият най-важен предмет от математиките, на английски се казва Theoretical Computer Science.
Занимава се с различни теоретични обекти, които могат да правят изчисления върху текстови низове.
Всичко свързано с анализ или шаблони върху текст използва нещата тук, а пък и отвъд.
Ако някога си чувал за машина на Тюринг, Тюринг-завършеност на програмни езици или проблемът за спирането, от тука идват.
Благодарение на тази наука е възможно да имплементираш компилатори на програмни езици и да правиш всички форми на разбор на текст (като обработката на уебстраници и интернет пакети).
-Записките са много добри, даже публично се намират, заедно с минали изпитни теми, [url http://logic.fmi.uni-sofia.bg/eai.html тук].
+Записките са много добри, даже публично се намират, заедно с минали изпитни теми, {url тук;http://logic.fmi.uni-sofia.bg/eai.html}.
И както по дискретни структури, асистентите не са консистентни и нивото малко криви.
Ама в края на деня преподавателите са готини и не искат да прецакват хора, така че се минава спокойно.
-[=Обектно ориентирано програмиране=]: това е най-популярният начин/парадигма за програмиране.
-Обект е групиране на данни с функциите върху тях, като са изпълнени [url https://en.wikipedia.org/wiki/Object-oriented_design#Object-oriented_concepts няколко свойства].
+{b Обектно ориентирано програмиране}: това е най-популярният начин/парадигма за програмиране.
+Обект е групиране на данни с функциите върху тях, като са изпълнени {url няколко свойства;https://en.wikipedia.org/wiki/Object-oriented_design#Object-oriented_concepts}.
Кажи-речи всяка компания и всеки модерен програмен език, който се използва в индустрията, поддържа ООП.
Екипът е същия като при УП, така че общото ми мнение е същото, макар че при ООП ситуацията е може би една идея по-релаксирана.
@@ -444,7 +422,7 @@
##### Зимен семестър
-[=Компютърни архитектури=]: описание на хардуера.
+{b Компютърни архитектури}: описание на хардуера.
Малко се доближава и до електротехниката, но се разглеждат много фундаменталните хардуерни компоненти и техните функционалности в един компютър.
Разглеждаме основните компонентни схеми за изчисления и хардуерно как се ползват и работят нещата.
Не е кой знае колко полезен за средния програмист, освен ако не се занимаваш със системно програмиране, ама е много важен фундамент.
@@ -453,22 +431,22 @@
Това е първият предмет при който няма задължителни упражнения, но никой не препоръчва да се ходи на избираемия практикум, понеже не е координиран много добре с лекциите и някои неща стават твърде трудни.
Иначе минаването е лесно.
-[=Основи на компютърната графика=]: има ли изобщо какво да обяснявам.
+{b Основи на компютърната графика}: има ли изобщо какво да обяснявам.
Разглеждаме част от математиката, но повече се занимаваме с 3D моделиране и идеите на сложните неща, не толкова тяхното имплементиране.
Минаването е лесно, трябва да си малко консистентен със седмичните задачи обаче.
И този лектор ми е един от любимите.
Презентациите в които се намира материала са перфектно направени и упражненията са много приятни.
-Ето [url https://boytchev.github.io/scorm/ тук] има редици малки задачки/игри с които можеше да изкараш малък бонус към оценката.
+Ето {url тук;https://boytchev.github.io/scorm/} има редици малки задачки/игри с които можеше да изкараш малък бонус към оценката.
-[=Структури от данни и програмиране=]: нещо като въведение в дизайн и анализ на алгоритмите.
+{b Структури от данни и програмиране}: нещо като въведение в дизайн и анализ на алгоритмите.
Занимаваме се с някои много важни структури от данни, като стек и опашка, и разглеждаме алгоритми върху тях.
Супер важно за всеки програмист.
Екипът пак е същия, както при УП и ООП, така че мнението ми продължава, но тук поне изискванията за писане на код са по-основателни.
Все пак разглеждаме конкретни структури от данни и алгоритми, ако не ги ползваш в решенията на задачи, малко би се обезсмислила цялата история.
-[=Функционално програмиране=]: втората най-използвана парадигма след ООП.
+{b Функционално програмиране}: втората най-използвана парадигма след ООП.
Идеята е, че разглеждаме всичко като функции, във всеки момент една функция връща нещо или приема нещо и никъде не пазим състояния.
Тоест, една стойност се намира или като аргумент или като върната стойност.
Също супер важно да се знае и може.
@@ -478,18 +456,18 @@
##### Летен семестър
-[=Алгебра 2=]: дефакто разглеждаме теория на групите, което на английски съм го виждал и като "Modern algebra".
+{b Алгебра 2}: дефакто разглеждаме теория на групите, което на английски съм го виждал и като "Modern algebra".
Група е някакво множество от елементи и операция върху тях, като за операцията са изпълнени няколко свойства.
Допълнително имаме и пръстен, където вече имаш множество и две операции върху тях.
-Може би звучи странно, но е една от [url https://www.youtube.com/watch?v=mH0oCDa74tE най-интересните и шантави математики].
+Може би звучи странно, но е една от {url най-интересните и шантави математики;https://www.youtube.com/watch?v=mH0oCDa74tE}.
Криптографията се основава на нея и има употреби в теория на графите.
Екипът същия като при Алгебра 1, така че нямам оплаквания.
Макар че този път няма седмични задачи - ура!
-[=Дизайн и анализ на алгоритми=]: също едно име, което обяснява себе си.
+{b Дизайн и анализ на алгоритми}: също едно име, което обяснява себе си.
Разглеждаме методиките за сравняване на алгоритми (асимптотика) и как да докажем тяхната коректност.
-Също разглеждаме доста основни и често използвани алгоритми, както и се допираме до [url https://en.wikipedia.org/wiki/NP_%28complexity%29 NP сложност].
+Също разглеждаме доста основни и често използвани алгоритми, както и се допираме до {url NP сложност;https://en.wikipedia.org/wiki/NP_%28complexity%29}.
Още един много важен предмет.
Тук сякаш асистентите преподават по-добре и нивото е по-изравнено.
@@ -497,7 +475,7 @@
Обаче смятам, че на доста моменти навлиза твърде много в математиката и теорията, и има същите проблеми с оценяването както по ДСТР.
Цели 15 човека минаха от първия път, така че нивото е горе-долу същото.
-[=Изследване на операциите=]: решава оптимизационни задачи, тоест задачи при които искаш минимум или максимум, като за всяка променлива имаш някакво ограничение (на английски се казва Linear Programming, но няма нищо общо с програмиране).
+{b Изследване на операциите}: решава оптимизационни задачи, тоест задачи при които искаш минимум или максимум, като за всяка променлива имаш някакво ограничение (на английски се казва Linear Programming, но няма нищо общо с програмиране).
Една оптимизационна задача е примерно ако имаме фабрики за автомобили, всяка произвеждаща различно количество коли и складове в други градове, с различни капацитети, и имаме цената на пътя между градовете и складовете, как най-евтно ще пренесем всички автомобили в складовете.
Има употреба ако се опитваш да решиш такъв тип задачи, но ми се струва от по-безполезните неща за един програмист.
@@ -505,7 +483,7 @@
Лекторът е готин.
Минаването е лесно, нещата не са супер трудни.
-[=Компютърни мрежи=]: пак име, което само се обяснява.
+{b Компютърни мрежи}: пак име, което само се обяснява.
Абсолютно всичко свързано с интернет и мрежите, от протоколи до методи за маршрутизация.
Като КАРХ не е от най-полезните за ежедневието, но е много важен фундамент.
@@ -513,7 +491,7 @@
Както и по други предмети, лектора не иска да ни прецаква, затова минаването не е проблем.
Даже бих казал, че е твърде лесно.
-[=Операционни системи=]: може би най-важният не-математически предмет, ако беше направен свестно.
+{b Операционни системи}: може би най-важният не-математически предмет, ако беше направен свестно.
Имам много силно мнение за него, като цяло предмета се свежда до 70% менижиране на процеси, 20% менижиране на памет и 10% случайни неща.
Имаше потенциалът да е от най-добрите предмети в целия бакалавър, ама програмата и изпитването беше наистина зле направено.
@@ -527,7 +505,7 @@
Не бих казал, че се учат стари неща, които не са актуални, но за най-новите технологии трябва да се обърнеш към избираеми.
Обучението е далеч от перфектно, обаче каквото и да си говорим, обучението никъде не е перфектно.
-Бих казал, че качеството на курсове също [url https://kleopetrov.me/2017/01/31/return-return-and-how-to-breack-it/ може да бъде много по-ниско].
+Бих казал, че качеството на курсове също {url може да бъде много по-ниско;https://kleopetrov.me/2017/01/31/return-return-and-how-to-breack-it/}.
Това е много голяма тема, обаче въпреки че не учим най-новите и използваемите неща, основите с които излизаш ти позволяват да научиш новите технологии значително по-бързо и в значително по-голяма дълбочина.
Колкото и да не се харесва, математиката е в основата на всички кътчета от компютрите.
Разбира се, има пре-достатъчно работа, която не изисква и елементарно събиране да знаеш, но ако се стремиш нагоре, математиката е нужна.
@@ -539,4 +517,6 @@
2. Студентстването като изживяване е веднъж в живота, все пак характерът става по-издържлив когато те скъсат по няколко изпита, за които си учил много.
3. Каквото и да си говорим, ФМИ е доста авторитетно учебно заведение, макар и диплома за един програмист да не е задължителна, със сигурност ще помогне значително.
-И даже бих аргументирал, че е [=по-добре да следваш една година във ФМИ и да се откажеш, отколкото да следваш 4 години и да завършиш в който и да е друг университет!=]
+И даже бих аргументирал, че е {b по-добре да следваш една година във ФМИ и да се откажеш, отколкото да следваш 4 години и да завършиш в който и да е друг университет!}
+
+{footnotes}
diff --git a/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du b/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du
index 1c6d67b..a4cd802 100644
--- a/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du
+++ b/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du
@@ -1,21 +1,21 @@
-# Friendship ended with Funtoo, now Gentoo is my best friend
+'def title Friendship ended with Funtoo, now Gentoo is my best friend
+'def desc Explaining why I switched from Funtoo to Gentoo as my main OS
-'define expected-reading 11 min
-'define created 28 May 2023
-'define edited 07 June 2023
-[$pagenav]
+# {title}
+
+{pagenav 11 min;28 May 2023;07 June 2023}
.contents
.numbered
-1. [url #terminology Terminology]
-2. [url #public-enemy-no-1-packages Public Enemy No 1: Packages]
-3. [url #i-didnt-follow-the-wolf-pack-philosophy I didn't follow the wolf pack philosophy]
-4. [url #why-did-i-choose-funtoo-in-the-first-place Why did I choose Funtoo in the first place?]
+1. {uhref Terminology}
+2. {uhref Public Enemy No 1: Packages}
+3. {uhref I didn't follow the wolf pack philosophy}
+4. {uhref Why did I choose Funtoo in the first place?}
.numbered
- 1. [url #debunking-benefits Debunking benefits]
- 2. [url #personal-advantages-over-gentoo Personal advantages over Gentoo]
+ 1. {uhref Debunking benefits}
+ 2. {uhref Personal advantages over Gentoo}
-Around 6 months ago I wrote [url /blog/taming-the-fun-too Taming The Fun-too], a blog post sharing my personal experiences with the Funtoo linux distribution.
+Around 6 months ago I wrote {url Taming The Fun-too;/blog/taming-the-fun-too}, a blog post sharing my personal experiences with the Funtoo linux distribution.
What you don't know is that less than a month later, at the end of December, I installed Gentoo on my desktop computer, and an additional 3 months later my laptop followed.
Here is what happened.
@@ -24,19 +24,19 @@ Here is what happened.
Before we begin, I want to take a second and explain some Gentoo/Funtoo terminology:
:unordered
-- [`emerge`] (as a verb): what does "install" mean? I would argue it means copying a program and the file it depends on somewhere on a system, with the goal of being able to run this program.
+- {` emerge} (as a verb): what does "install" mean? I would argue it means copying a program and the file it depends on somewhere on a system, with the goal of being able to run this program.
.p
Now, in Gentoo and Funtoo, most programs are compiled from source code, so before you install you download it's source and compile.
- For this reason, on such systems you would usually say a certain program/package is [*being emerged, not installed*] (and the words comes from the [url https://wiki.gentoo.org/wiki/Emerge package-manager command-line utility of the same name]).
+ For this reason, on such systems you would usually say a certain program/package is {i being emerged, not installed} (and the words comes from the {url package-manager command-line utility of the same name;https://wiki.gentoo.org/wiki/Emerge}).
-- [`ebuild`] (file): the exact steps needed to emerge a package differ from one project to another, but how do you manage packages then?
+- {` ebuild} (file): the exact steps needed to emerge a package differ from one project to another, but how do you manage packages then?
The solution is that when you try to emerge something, a special file with detailed instructions is looked up: an ebuild file.
- repository tree: the collection of all ebuilds
-- [`use`] flags: every program can be built with different flags (aka options), which enable or disable certain features from being available in the result package.
- For example, the text editor [url https://packages.gentoo.org/packages/app-editors/vim vim] supports sound, but not everyone would want to have that feature.
+- {` use} flags: every program can be built with different flags (aka options), which enable or disable certain features from being available in the result package.
+ For example, the text editor {url vim;https://packages.gentoo.org/packages/app-editors/vim} supports sound, but not everyone would want to have that feature.
## Public Enemy No 1: Packages
@@ -47,41 +47,41 @@ Most packages and their dependencies on Funtoo go unmaintained and untested for
'footnote required-3.8 Required might be a strong word, I don't remember if I tried (though I'm sure I did) just downgrading the Python version in the ebuild. Nevertheless, there were for sure useful packages which really did need it.
-Python was stuck at version 3.7, while a lot of packages like barrier, libplacebo, mpv and pulseeffects[$packages-in-repo-tree] required[$required-3.8] at least 3.8.
+Python was stuck at version 3.7, while a lot of packages like barrier, libplacebo, mpv and pulseeffects{packages-in-repo-tree} required{required-3.8} at least 3.8.
So, with a lot of effort and poking around, I got python 3.8 to work, just barely.
-What's even better is that eventually I reached an [=unfixable=] circular python dependency (between dev-python/packaging and dev-python/setuptools).
+What's even better is that eventually I reached an {b unfixable} circular python dependency (between dev-python/packaging and dev-python/setuptools).
-'footnote glibc This point may not be completely fair, since Funtoo has a system for [url https://web.archive.org/web/20230528115518/https://projects.funtoo.org/metatools/docs/autogen.html ebuild generation], which means that they might've made configuration changes and/or applied patches which "fix" that version, but still, it really isn't a good look.
+'footnote glibc This point may not be completely fair, since Funtoo has a system for {url ebuild generation;https://web.archive.org/web/20230528115518/https://projects.funtoo.org/metatools/docs/autogen.html}, which means that they might've made configuration changes and/or applied patches which "fix" that version, but still, it really isn't a good look.
-Another problem child was glibc, it is [*currently*] at [url https://github.com/funtoo/core-kit/tree/1.4-release/sys-libs/glibc version 2.33-r2], which under Gentoo [url https://gitweb.gentoo.org/repo/gentoo.git/tree/profiles/package.mask#n542 is officially masked and discouraged for usage][$glibc] and wouldn't you know it, also prevents some packages from being compiled (mainly I remember ungoogled-chromium).
+Another problem child was glibc, it is {i currently} at {url version 2.33-r2;https://github.com/funtoo/core-kit/tree/1.4-release/sys-libs/glibc}, which under Gentoo {url is officially masked and discouraged for usage;https://gitweb.gentoo.org/repo/gentoo.git/tree/profiles/package.mask#n542}{glibc} and wouldn't you know it, also prevents some packages from being compiled (mainly I remember ungoogled-chromium).
There were a lot more problematic packages, but I've forgotten most details.
What I do remember is that the day I decided to hop to Gentoo, I tried to update my system and yet again I got some sort of issue, either a package couldn't compile properly or there was some dependency conflict.
That was preceded by my unsuccessful attempts at getting the kicad package to work a couple of days prior.
At that point, this had become completely normal.
-[=But=] Funtoo shouldn't be blamed for it!
+{b But} Funtoo shouldn't be blamed for it!
## I didn't follow the wolf pack philosophy
-On the [url https://www.funtoo.org/Welcome Welcome] page of Funtoo's website, in the second paragraph, we are linked the [url https://www.funtoo.org/Wolf_Pack_Philosophy Wolf Pack Philosophy] page.
+On the {url Welcome;https://www.funtoo.org/Welcome} page of Funtoo's website, in the second paragraph, we are linked the {url Wolf Pack Philosophy;https://www.funtoo.org/Wolf_Pack_Philosophy} page.
This is essentially a document describing how a member of the community should behave, and I didn't follow it.
Any member of the pack is supposed to:
.unordered
-- [=Be Mindful of the Pack=] by tackling challenges with the community\n
+- {b Be Mindful of the Pack} by tackling challenges with the community\n
but as I found (package) challenges, I tackled them on my own, not trying to consult anyone or ask for help
-- [=Be Interconnected=] by supporting and being supported by the community\n
+- {b Be Interconnected} by supporting and being supported by the community\n
but I didn't connect with anyone on my issues
-- [=Howl=] by expressing their needs and sharing their "adventures"\n
+- {b Howl} by expressing their needs and sharing their "adventures"\n
but I didn't express them and didn't share the work I've done
Or more simply put, Funtoo is a small project, and you need to communicate with others to get things done.
-'footnote kicad On that aforementioned kicad package, drobbins, the benevolent dictator for life of Funtoo, categorized it as a [url https://bugs.funtoo.org/browse/FL-8435?focusedId=52907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-52907 package which people aren't interested in].
+'footnote kicad On that aforementioned kicad package, drobbins, the benevolent dictator for life of Funtoo, categorized it as a {url package which people aren't interested in;https://bugs.funtoo.org/browse/FL-8435?focusedId=52907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-52907}.
-Another way to look at it is that in a project of this scale, what gets supported is what the community uses, so in a way, I was trying to use Funtoo in the [*wrong*] way.
+Another way to look at it is that in a project of this scale, what gets supported is what the community uses, so in a way, I was trying to use Funtoo in the {i wrong} way.
This may sound ridiculous, but then again, they aren't making a project which "just works" for everyone (like Ubuntu or Linux Mint), this is a project by the community for the community.
-You can't expect them to support everything that a big-scale distro does, like Gentoo, with a fraction of the manpower, so if nobody supports a package (which exists in the repository tree) that doesn't work and you don't at least speak up, it will probably stay broken[$kicad] (this kind of relates to the [=Is Territorial=] point in the philosophy).
+You can't expect them to support everything that a big-scale distro does, like Gentoo, with a fraction of the manpower, so if nobody supports a package (which exists in the repository tree) that doesn't work and you don't at least speak up, it will probably stay broken{kicad} (this kind of relates to the {b Is Territorial} point in the philosophy).
However, in my defense, I didn't open bug reports or create forum posts because my issues weren't "directly" related to Funtoo, or a normal Funtoo installation.
Most of the time I would have an issue with a package, then get it's Gentoo counterpart, try to get all dependencies working one by one, and it will fail with some unsearchable error.
@@ -102,12 +102,12 @@ Looking at these with the benefit of hindsight:
.quote git > rsync
By default, on Gentoo synchronization of ebuild files is done via rsync, while on Funtoo it's done with git.
-Gentoo has actually supported git synchronization for quite a while, and [url https://wiki.gentoo.org/wiki/Portage_with_Git the setup is easy], so in the modern day it's really a matter of preference.
-Though, [url https://lwn.net/Articles/759578/ rsync is probably better with bad internet connections].
+Gentoo has actually supported git synchronization for quite a while, and {url the setup is easy;https://wiki.gentoo.org/wiki/Portage_with_Git}, so in the modern day it's really a matter of preference.
+Though, {url rsync is probably better with bad internet connections;https://lwn.net/Articles/759578/}.
.quote profiles (flavors and mix-ins)
-Funtoo has a system called [url https://www.funtoo.org/Funtoo_Profiles profiles].
+Funtoo has a system called {url profiles;https://www.funtoo.org/Funtoo_Profiles}.
The idea is that you can group a whole set of packages and use flags into one name with the ability to turn them off and on again.
So, if you want to install gnome on your system, you don't have to worry about flags and potential dependency problems, just use the gnome mix-in and everything will be ready to go for emerging.
@@ -115,19 +115,19 @@ This is pretty cool but it's also somewhat unnecessary.
You would save time on your very first install ever, but once you've set your flags on one machine, you'll just need to copy some files over (make.conf and package.use) and be done with it.
There is a case to be made for people who often emerge and unmerge packages, but they are very much a minority (which I'm not a part of).
-.quote Funtoo has [url https://wiki.gentoo.org/wiki/Stage_tarball stage 3 tarballs] with already setup DEs
+.quote Funtoo has {url stage 3 tarballs;https://wiki.gentoo.org/wiki/Stage_tarball} with already setup DEs
This means that on a Funtoo system, you could directly unpack the tarball (the initial prebuilt binaries), and without emerging anything, have a ready-to-go desktop environment.
The huge benefit is that you can very quickly reboot into your "install" (after setting up the booting of course), and use your computer with the comfort of a graphical environment while everything else is being emerged.
-Again, this is really cool, but at the end of the day, a normal "text-only" installation isn't very difficult, the [url https://wiki.gentoo.org/wiki/Handbook:AMD64/Full/Installation Gentoo handbook] is very detailed and well written, you install a system once so in the long term it wouldn't matter and I personally use a custom desktop environment setup, so those DEs would be bloat.
+Again, this is really cool, but at the end of the day, a normal "text-only" installation isn't very difficult, the {url Gentoo handbook;https://wiki.gentoo.org/wiki/Handbook:AMD64/Full/Installation} is very detailed and well written, you install a system once so in the long term it wouldn't matter and I personally use a custom desktop environment setup, so those DEs would be bloat.
.quote fixed release model
-[url https://forums.funtoo.org/topic/1945-funtoo-release-model/#comment-9321 Funtoo releases fixed version of their distro], which means, in theory, packages will be way more stable and tested than normally.
+{url Funtoo releases fixed version of their distro;https://forums.funtoo.org/topic/1945-funtoo-release-model/#comment-9321}, which means, in theory, packages will be way more stable and tested than normally.
I've never found problems with packages being "too new", and this is more relevant to how the packages are managed by the maintainers, so it doesn't make that much of a difference to the end user, in my opinion.
-.quote [url https://www.funtoo.org/Autogen autogens]
+.quote {url autogens;https://www.funtoo.org/Autogen}
Rather than making ebuilds manually, on Funtoo you can automatically generate them with simple Python code.
This system probably reduces management time quite a lot, especially for a smaller team of maintainers, but you would still need to understand ebuild files.
@@ -146,8 +146,8 @@ Unfortunately, for Gentoo it's the opposite effect, I couldn't compile most pack
.quote package.use > make.conf
-There is a big emphasis on writing your use flags in a separate [`/etc/portage/package.use`] file (or make it a folder and add use flags in different subfiles), and to try and change [`/etc/portage/make.conf`] as little as possible.
-I generally believe this is a significantly better system than stuffing everything into [`make.conf`], and it isn't pushed that hard on Gentoo.
+There is a big emphasis on writing your use flags in a separate {` /etc/portage/package.use} file (or make it a folder and add use flags in different subfiles), and to try and change {` /etc/portage/make.conf} as little as possible.
+I generally believe this is a significantly better system than stuffing everything into {` make.conf}, and it isn't pushed that hard on Gentoo.
That said, Gentoo still supports it, so I'm not missing out, but I probably wouldn't have used it.
diff --git a/src/blog/gns3-initsh-no-such-file/index.du b/src/blog/gns3-initsh-no-such-file/index.du
index 2b6f908..fdd666e 100644
--- a/src/blog/gns3-initsh-no-such-file/index.du
+++ b/src/blog/gns3-initsh-no-such-file/index.du
@@ -1,12 +1,12 @@
-# Fix "exec /gns3/init.sh: no such file or directory"
+'def title Fix 'exec /gns3/init.sh: no such file or directory'
+'def desc This problem occurs on new installations, the solution is to make GNS3 use Debian's busybox implementation.
-'define expected-reading 1 min
-'define created 14 June 2023
-'define edited 14 June 2023
-[$pagenav]
+# {title}
+
+{pagenav 1 min;14 June 2023;14 June 2023}
This problem can easily occur on new installations and can be hard to figure out.
-In a [url https://github.com/GNS3/gns3-server/issues/2069#issuecomment-1296741195 GitHub issue], the solution that fixed it for me was using Debian's busybox:
+In a {url GitHub issue;https://github.com/GNS3/gns3-server/issues/2069#issuecomment-1296741195}, the solution that fixed it for me was using Debian's busybox:
:ordered
0. Get into a temporary folder
diff --git a/src/blog/how-to-encrypt-email/index.du b/src/blog/how-to-encrypt-email/index.du
index ec9d546..13b49a5 100644
--- a/src/blog/how-to-encrypt-email/index.du
+++ b/src/blog/how-to-encrypt-email/index.du
@@ -1,70 +1,70 @@
-# How to encrypt email
+'def title How to encrypt email
+'def desc For PGP add keys in your client. For S/MIME another article is linked. Also contains a comparison of a lot of mail clients.
-'define expected-reading 5 min
-'define created 16 September 2022
-'define edited 16 November 2022
-[$pagenav]
+# {title}
+
+{pagenav 5 min;16 September 2022;16 November 2022}
:contents
:numbered
-1. [url #getting-keys Getting keys]
+1. {uhref Getting keys}
:numbered
- 1. [url #pgp PGP]
+ 1. {uhref PGP}
.numbered
- 1. [url #pgptool.org pgptool.org]
- 2. [url #gnu-privacy-guard GNU Privacy Guard]
+ 1. {uhref pgptool.org}
+ 2. {uhref GNU Privacy Guard}
- 2. [url #smime S/MIME]
+ 2. {uhref S/MIME}
-2. [url #exchanging-keys Exchanging keys]
-3. [url #configuring-clients Configuring clients]
+2. {uhref Exchanging keys}
+3. {uhref Configuring clients}
-In [url /blog/encrypted-email this] blog post I shared the most common technologies for email encryption and a bit of how they work. PGP and S/MIME are the most popular schemes, with support from a lot of clients.
+In {url this;/blog/encrypted-email} blog post I shared the most common technologies for email encryption and a bit of how they work. PGP and S/MIME are the most popular schemes, with support from a lot of clients.
These are all the steps required to go from having no encryption, to encrypting all of your future emails.
## Getting keys
-PGP and S/MIME are both built upon [url https://en.wikipedia.org/wiki/Public-key_cryptography public-key cryptography] so you and all of your recipients need to have a pair of public and private keys.
+PGP and S/MIME are both built upon {url public-key cryptography;https://en.wikipedia.org/wiki/Public-key_cryptography} so you and all of your recipients need to have a pair of public and private keys.
### PGP
-As [url /blog/encrypted-email/#pgp discussed], PGP relies on a [url https://en.wikipedia.org/wiki/Web_of_trust web of trust], meaning you can generate your keys by yourself.
+As {url discussed;/blog/encrypted-email/#pgp}, PGP relies on a {url web of trust;https://en.wikipedia.org/wiki/Web_of_trust}, meaning you can generate your keys by yourself.
#### pgptool.org
-By far, the easiest way to do this is via the website [url https://pgptool.org/ pgptool.org]. Just open the link, fill out your details, select the recommended values (select never as your expiration time) and wait a couple minutes. After they are done, you can click the two red buttons to download your public and private keys.
+By far, the easiest way to do this is via the website {url pgptool.org;https://pgptool.org/}. Just open the link, fill out your details, select the recommended values (select never as your expiration time) and wait a couple minutes. After they are done, you can click the two red buttons to download your public and private keys.
#### GNU Privacy Guard
-As an alternative, you can use a desktop program. The most popular one is [url https://www.gnupg.org/ GNU Privacy Guard] (GPG for short). It is [url https://gnupg.org/download/#binary available] on most desktop operating systems, including [url https://gpg4win.org/download.html Windows] and [url https://gpgtools.org/ MacOS].
+As an alternative, you can use a desktop program. The most popular one is {url GNU Privacy Guard;https://www.gnupg.org/} (GPG for short). It is {url available;https://gnupg.org/download/#binary} on most desktop operating systems, including {url Windows;https://gpg4win.org/download.html} and {url MacOS;https://gpgtools.org/}.
-The [*Windows*] version comes with a graphical user interface, so it's easiest to use that:
+The {i Windows} version comes with a graphical user interface, so it's easiest to use that:
:ordered
1. Open the application "Kleopatra"
-2. Click on [`File`] -> [`New Certificate`]
+2. Click on {` File} -> {` New Certificate}
-3. Input your details and press [`OK`]
+3. Input your details and press {` OK}
.bulleted
- - Feel free to click on [`Advanced Settings`] and look if if the value for [`RSA`] is [`4096 bit`], the value for [`+ RSA`] is enabled and is [`4096 bits`], and finally both [`Signing`] and [`Authentication`] are selected
+ - Feel free to click on {` Advanced Settings} and look if if the value for {` RSA} is {` 4096 bit}, the value for {` + RSA} is enabled and is {` 4096 bits}, and finally both {` Signing} and {` Authentication} are selected
-4. On the next screen, press [`Create`]
+4. On the next screen, press {` Create}
5. You'll be asked for a password. Make one up, and enter it, but do not forget it!
.bulleted
- - The password is used for your private key. If anyone gets ahold if it, they [=will=] be able to impersonate you. A password makes sure that doesn't happen, at least until you tell everyone that your key was leaked.
+ - The password is used for your private key. If anyone gets ahold if it, they {b will} be able to impersonate you. A password makes sure that doesn't happen, at least until you tell everyone that your key was leaked.
-6. On the final screen, click [`Finish`]
+6. On the final screen, click {` Finish}
-7. To help with the next chapter, we'll extract your public key. In "Kleopatra" you should see a line, containing your name and email. Right-click on it, and select [`Export Certificate`].
+7. To help with the next chapter, we'll extract your public key. In "Kleopatra" you should see a line, containing your name and email. Right-click on it, and select {` Export Certificate}.
-On [*Linux*] and [*MacOS*], you can use the command line:
+On {i Linux} and {i MacOS}, you can use the command line:
:ordered
1. Enter this command in your favorite terminal
@@ -72,7 +72,7 @@ On [*Linux*] and [*MacOS*], you can use the command line:
```bash
gpg --full-generate-key
-2. Follow the prompt on the screen (sample pictures available in [url https://www.encryptionconsulting.com/how-to-generate-pgp-key-pair/ encryptionconsulting.com])
+2. Follow the prompt on the screen (sample pictures available in {url encryptionconsulting.com;https://www.encryptionconsulting.com/how-to-generate-pgp-key-pair/})
3. Export your public key (of course, change me@email.com and the location to the one you want, but don't forget the .asc extension)
@@ -82,15 +82,15 @@ gpg --armor --export me@email.com > ~/Documents/me-email.com-publickey.asc
### S/MIME
-Contrary to PGP, S/MIME relies on a certificate authority, meaning you'll have to buy your keys from someone. Any provider from [url https://support.google.com/a/answer/7448393?hl=en&ref_topic=9061730 Google]'s list of trusted CAs will work.
+Contrary to PGP, S/MIME relies on a certificate authority, meaning you'll have to buy your keys from someone. Any provider from {url Google;https://support.google.com/a/answer/7448393?hl=en&ref_topic=9061730}'s list of trusted CAs will work.
-Currently, the only one that provides free certificates is [url https://www.actalis.com/s-mime-certificates.aspx Actalis]. Their process is pretty straight forward, just follow the instructions (shown in [url https://www.dannyguo.com/blog/how-to-get-a-free-s-mime-certificate/ this] article).
+Currently, the only one that provides free certificates is {url Actalis;https://www.actalis.com/s-mime-certificates.aspx}. Their process is pretty straight forward, just follow the instructions (shown in {url this;https://www.dannyguo.com/blog/how-to-get-a-free-s-mime-certificate/} article).
## Exchanging keys
You should now have a text file with your public key in it. When you want to send an encrypted email to someone, ask them for their public key, and meanwhile send them your public key. It doesn't matter how you do that, even if it's with unencrypted emails.
-Remember, [=never=] send your [=private=] key to anyone!
+Remember, {b never} send your {b private} key to anyone!
## Configuring clients
@@ -98,13 +98,14 @@ Now we need to configure your email application to automatically encrypt and dec
When writing a message, don't forget to check if encryption is turned on for this email! On most clients, in the compose window, you'll have to select an option to enable encryption, but others do that automatically.
-[*Freemium means it has a free and a paid tier. Premium means you have to pay for it. FOSS means it's free and open source. FreemiumOSS means it is free and open source, but also has paid tiers.*]
+{i Freemium means it has a free and a paid tier. Premium means you have to pay for it. FOSS means it's free and open source. FreemiumOSS means it is free and open source, but also has paid tiers.}
-:table_6
-'define 1 [^[url #1 1]^]
-'define 2 [^[url #2 2]^]
-'define 3 [^[url #3 3]^]
-'define * [^[url #* *]^]
+:table
+:6
+'def 1 {^ {url 1;#1}}
+'def 2 {^ {url 2;#2}}
+'def 3 {^ {url 3;#3}}
+'def * {^ {url *;#*}}
|= Client
|= Type
@@ -123,23 +124,23 @@ When writing a message, don't forget to check if encryption is turned on for thi
|: Gmail
|: Freemium
|: Web
-|: [url https://flowcrypt.com/ Yes][$1]
-|: [url https://flowcrypt.com/ Yes][$1]
-|: [url https://support.google.com/a/answer/6374496?hl=en&ref_topic=9061730 Yes][$2]
+|: {url Yes;https://flowcrypt.com/}{1}
+|: {url Yes;https://flowcrypt.com/}{1}
+|: {url Yes;https://support.google.com/a/answer/6374496?hl=en&ref_topic=9061730}{2}
|: Outlook
|: Freemium
|: Web
|: No
|: No
-|: [url https:://support.microsoft.com/en-us/office/encrypt-email-messages-373339cb-bf1a-4509-b296-802a39d801dc#bkmk_encryptwithsmime Yes][$2]
+|: {url Yes;https:://support.microsoft.com/en-us/office/encrypt-email-messages-373339cb-bf1a-4509-b296-802a39d801dc#bkmk_encryptwithsmime}{2}
|: iCloud mail
|: Freemium
|: Web
-|: [url https://support.apple.com/en-us/HT201214 Yes]
-|: [url https://support.apple.com/en-us/HT201214 Yes]
-|: [url https://support.apple.com/en-us/HT202345 Yes]
+|: {url Yes;https://support.apple.com/en-us/HT201214}
+|: {url Yes;https://support.apple.com/en-us/HT201214}
+|: {url Yes;https://support.apple.com/en-us/HT202345}
|: Yahoo!
|: Freemium
@@ -151,22 +152,22 @@ When writing a message, don't forget to check if encryption is turned on for thi
|: Protonmail
|: Freemium
|: Web
-|: [url https://proton.me/support/how-to-use-pgp Yes]
-|: [url https://proton.me/support/how-to-use-pgp Yes]
+|: {url Yes;https://proton.me/support/how-to-use-pgp}
+|: {url Yes;https://proton.me/support/how-to-use-pgp}
|: No
|: Roundcube
|: Self-hosted
|: Web
-|: [url https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma Yes][$1]
-|: [url https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma Yes][$1]
-|: [url https://github.com/roundcube/roundcubemail/issues/4977 No]
+|: {url Yes;https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma}{1}
+|: {url Yes;https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma}{1}
+|: {url No;https://github.com/roundcube/roundcubemail/issues/4977}
|: Rainloop
|: Self-hosted
|: Web
|: Yes
-|: [url https://github.com/RainLoop/rainloop-webmail/issues/1798 No]
+|: {url No;https://github.com/RainLoop/rainloop-webmail/issues/1798}
|: No
|= Desktop
@@ -179,44 +180,44 @@ When writing a message, don't forget to check if encryption is turned on for thi
|: Thunderbird
|: FOSS
|: Windows, MacOS, Linux
-|: [url https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq#w_i-have-never-used-openpgp-with-thunderbird-before-how-do-i-setup-openpgp Yes]
-|: [url https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq#w_i-have-never-used-openpgp-with-thunderbird-before-how-do-i-setup-openpgp Yes]
-|: [url https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq Yes]
+|: {url Yes;https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq#w_i-have-never-used-openpgp-with-thunderbird-before-how-do-i-setup-openpgp}
+|: {url Yes;https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq#w_i-have-never-used-openpgp-with-thunderbird-before-how-do-i-setup-openpgp}
+|: {url Yes;https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq}
|: Outlook
|: Premium
|: Windows, MacOS
|: No
|: No
-|: [url https://support.microsoft.com/en-us/office/encrypt-email-messages-373339cb-bf1a-4509-b296-802a39d801dc#bkmk_encryptwithsmime Yes]
+|: {url Yes;https://support.microsoft.com/en-us/office/encrypt-email-messages-373339cb-bf1a-4509-b296-802a39d801dc#bkmk_encryptwithsmime}
|: Mailbird
|: Premium
|: Windows
-|: [url https://mailbird.featureupvote.com/suggestions/74494/pgp-encryption-support No]
-|: [url https://mailbird.featureupvote.com/suggestions/74494/pgp-encryption-support No]
-|: [url https://mailbird.featureupvote.com/suggestions/160861/smime-support No]
+|: {url No;https://mailbird.featureupvote.com/suggestions/74494/pgp-encryption-support}
+|: {url No;https://mailbird.featureupvote.com/suggestions/74494/pgp-encryption-support}
+|: {url No;https://mailbird.featureupvote.com/suggestions/160861/smime-support}
|: Evolution
|: FOSS
|: Linux
-|: [url https://help.gnome.org/users/evolution/stable/mail-encryption-gpg-set-up.html.en Yes]
-|: [url https://help.gnome.org/users/evolution/stable/mail-encryption-gpg-set-up.html.en Yes]
-|: [url https://help.gnome.org/users/evolution/stable/mail-encryption-s-mime-manage.html.en Yes]
+|: {url Yes;https://help.gnome.org/users/evolution/stable/mail-encryption-gpg-set-up.html.en}
+|: {url Yes;https://help.gnome.org/users/evolution/stable/mail-encryption-gpg-set-up.html.en}
+|: {url Yes;https://help.gnome.org/users/evolution/stable/mail-encryption-s-mime-manage.html.en}
|: Sylpheed
|: FOSS
|: Windows, MacOS, Linux
-|: [url https://sylpheed.sraoss.jp/doc/manual/en/sylpheed-8.html#ss8.2 Yes]
-|: [url https://sylpheed.sraoss.jp/doc/manual/en/sylpheed-8.html#ss8.2 Yes]
-|: [url https://www.sraoss.jp/pipermail/sylpheed/2011-May/004551.html No]
+|: {url Yes;https://sylpheed.sraoss.jp/doc/manual/en/sylpheed-8.html#ss8.2}
+|: {url Yes;https://sylpheed.sraoss.jp/doc/manual/en/sylpheed-8.html#ss8.2}
+|: {url No;https://www.sraoss.jp/pipermail/sylpheed/2011-May/004551.html}
|: Claws-mail
|: FOSS
|: Windows, Linux
-|: [url https://claws-mail.org/plugin.:php?plugin=gpg Yes][$1]
-|: [url https://claws-mail.org/plugin.php?plugin=gpg Yes][$1]
-|: [url https://claws-mail.org/plugins.php Yes][$1]
+|: {url Yes;https://claws-mail.org/plugin.:php?plugin=gpg}{1}
+|: {url Yes;https://claws-mail.org/plugin.php?plugin=gpg}{1}
+|: {url Yes;https://claws-mail.org/plugins.php}{1}
|= Mobile
|:
@@ -230,14 +231,14 @@ When writing a message, don't forget to check if encryption is turned on for thi
|: Android, iOS
|: No
|: No
-|: Yes[$3]
+|: Yes{3}
|: Outlook
|: Free
|: Android, iOS
|: No
|: No
-|: Yes[$3]
+|: Yes{3}
|: Apple Mail
|: Free
@@ -263,26 +264,30 @@ When writing a message, don't forget to check if encryption is turned on for thi
|: Protonmail
|: Free
|: Android, iOS
-|: [url https://proton.me/support/how-to-use-pgp Yes]
-|: [url https://proton.me/support/how-to-use-pgp Yes]
+|: {url Yes;https://proton.me/support/how-to-use-pgp}
+|: {url Yes;https://proton.me/support/how-to-use-pgp}
|: No
|: K-9 Mail
|: FOSS
|: Android
-|: [url https://docs.k9mail.app/en/current/security/pgp/ Yes]
-|: [url https://docs.k9mail.app/en/current/security/pgp/ Yes]
-|: [url https://docs.k9mail.app/en/current/security/overview/#end-to-end-encryption No]
+|: {url Yes;https://docs.k9mail.app/en/current/security/pgp/}
+|: {url Yes;https://docs.k9mail.app/en/current/security/pgp/}
+|: {url No;https://docs.k9mail.app/en/current/security/overview/#end-to-end-encryption}
|: FairEmail
|: FreemiumOSS
|: Android
-|: [url https://github.com/M66B/FairEmail/blob/master/FAQ.md Yes]
-|: [url https://github.com/M66B/FairEmail/blob/master/FAQ.md Yes]
-|: [url https://github.com/M66B/FairEmail/blob/master/FAQ.md Yes][$*]
+|: {url Yes;https://github.com/M66B/FairEmail/blob/master/FAQ.md}
+|: {url Yes;https://github.com/M66B/FairEmail/blob/master/FAQ.md}
+|: {url Yes;https://github.com/M66B/FairEmail/blob/master/FAQ.md}{*}
+
-<span id="1">[^1^]</span> Available with an extension/plugin\n
-<span id="2">[^2^]</span> Available in a paid version of the software (assuming the software is Freemium; this is true for all Premium software)\n
-<span id="3">[^3^]</span> Available with a Premium account (even if the software is Free)\n
-<span id="*">[^*^]</span> You can read S/MIME messages, but signing and encrypting is a pro feature
+<span id="1">{^ 1}</span> Available with an extension/plugin\n
+<span id="2">{^ 2}</span> Available in a paid version of the software (assuming the software is Freemium; this is true for all Premium software)\n
+<span id="3">{^ 3}</span> Available with a Premium account (even if the software is Free)\n
+<span id="*">{^ *}</span> You can read S/MIME messages, but signing and encrypting is a pro feature
+'def 1
+'def 2
+'def 3
diff --git a/src/blog/how-to-use-jira/bug.du b/src/blog/how-to-use-jira/bug.du
index d776367..3b29ef3 100644
--- a/src/blog/how-to-use-jira/bug.du
+++ b/src/blog/how-to-use-jira/bug.du
@@ -1,21 +1,18 @@
-# Bug tracking template - How to use Jira
+'def title Bug tracking template - How to use Jira
+'def desc The bug tracking template offers only issue tracking, no boards, no cards, no backlog.
-'define expected-reading 1 min
-'define created 24 July 2020
-'define edited 16 September 2020
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./scrum.html Scrum template
-'define next_link ./releases.html Releases
-[$pagination_middle]
+{pagenav 1 min;24 July 2020;edited 16 September 2020}
-The Bug Tracking template is completely different from the [url ./scrum.html Scrum] and [url ./kanban.html Kanban] templates, because it [=offers only issue tracking=].
+{pagination ./;Scrum template;./scrum.html;Releases;./releases.html}
-[=There are no boards, no cards, no backlog=]. All issues are accessed from the [`Issues`] page from the sidebar.
+The Bug Tracking template is completely different from the {url Scrum;./scrum.html} and {url Kanban;./kanban.html} templates, because it {b offers only issue tracking}.
-[image ./img/issues-sidebar.png]
+{b There are no boards, no cards, no backlog}. All issues are accessed from the {` Issues} page from the sidebar.
-That's why this template is [=available only when creating a project=].
+{img ./img/issues-sidebar.png}
-Of course, [=you can add boards at any time=], but this project template doesn't add any by itself.
+That's why this template is {b available only when creating a project}.
+
+Of course, {b you can add boards at any time}, but this project template doesn't add any by itself.
diff --git a/src/blog/how-to-use-jira/cards.du b/src/blog/how-to-use-jira/cards.du
index 8a5f1b7..a2bcb1d 100644
--- a/src/blog/how-to-use-jira/cards.du
+++ b/src/blog/how-to-use-jira/cards.du
@@ -1,161 +1,158 @@
-# Cards - How to use Jira
+'def title Cards - How to use Jira
+'def desc Each issue is represented as an object with properties. More specifically, these objects are called 'cards'.
-'define expected-reading 4 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./filters.html Filters
-'define next_link ./projects.html Projects
-[$pagination_middle]
+{pagenav 4 min;24 July 2020;03 June 2021}
+
+{pagination ./;Filters;./filters.html;Projects;./projects.html}
.contents
.numbered
-1. [url #properties Properties]
-2. [url #creating Creating]
-3. [url #viewing Viewing]
-4. [url #how-to-use How to use]
+1. {uhref Properties}
+2. {uhref Creating}
+3. {uhref Viewing}
+4. {uhref How to use}
.numbered
- 1. [url #right-side Right side]
- 2. [url #work-log Work log]
- 3. [url #issue-flagging Issue flagging]
- 4. [url #basic-issue-information Basic issue information]
+ 1. {uhref Right side}
+ 2. {uhref Work log}
+ 3. {uhref Issue flagging}
+ 4. {uhref Basic issue information}
-[=Each issue is represented as an object with properties=]. More specifically, these objects are called 'cards'.
+{b Each issue is represented as an object with properties}. More specifically, these objects are called 'cards'.
-[image ./img/kanban-cards.png]
+{img ./img/kanban-cards.png}
## Properties
Each card has the following properties:
-[image ./img/fields-cards.png]
+{img ./img/fields-cards.png}
:unordered
-- [=Project=] - the [url ./projects.html project] this card is stored in
+- {b Project} - the {url project;./projects.html} this card is stored in
- [image ./img/project-create-card.png]
+ {img ./img/project-create-card.png}
-- [=Issue type=] - the basic purpose of an issue (Improvement, Bug, ...)
+- {b Issue type} - the basic purpose of an issue (Improvement, Bug, ...)
- [image ./img/issue-types.png]
+ {img ./img/issue-types.png}
:bulleted
- - [image ./img/story-type.png Story] - functionality or feature expressed as a goal, something like "As a user, I want to be able to pay for my order via PayPal"
+ - {img Story;./img/story-type.png} - functionality or feature expressed as a goal, something like "As a user, I want to be able to pay for my order via PayPal"
- - [image ./img/bug-type.png Bug] - a problem/error
+ - {img Bug;./img/bug-type.png} - a problem/error
- - [image ./img/epic-type.png Epic] - a collection of issues, issues are linked through 'Epic link' (see below)
+ - {img Epic;./img/epic-type.png} - a collection of issues, issues are linked through 'Epic link' (see below)
- - [image ./img/task-type.png Task] - a small piece of work
+ - {img Task;./img/task-type.png} - a small piece of work
- - [image ./img/sub-task-type.png Sub-task] - an issue that is directly connected to another issue. This is used for when a given issue needs to be broken down into separate even smaller issues.
+ - {img Sub-task;./img/sub-task-type.png} - an issue that is directly connected to another issue. This is used for when a given issue needs to be broken down into separate even smaller issues.
-- [=Summary=] - a (required) brief explanation of the issue
+- {b Summary} - a (required) brief explanation of the issue
- [image ./img/summary-create-card.png]
+ {img ./img/summary-create-card.png}
-- [=Description=] - detailed explanation of the issue
+- {b Description} - detailed explanation of the issue
- [image ./img/description-create-card.png]
+ {img ./img/description-create-card.png}
-- [=Reporter=] - person who created the issue
+- {b Reporter} - person who created the issue
- [image ./img/reporter-create-card.png]
+ {img ./img/reporter-create-card.png}
-- [=Assignee=] - person who will work on the issue
+- {b Assignee} - person who will work on the issue
- [image ./img/assignee-create-card.png]
+ {img ./img/assignee-create-card.png}
-- [=Labels=] - tags with which you can organise even more the issue
+- {b Labels} - tags with which you can organise even more the issue
- [image ./img/label-create-card.png]
+ {img ./img/label-create-card.png}
-- [=Epic link=] - link of issue with type Epic
+- {b Epic link} - link of issue with type Epic
- [image ./img/epic-link-create-card.png]
+ {img ./img/epic-link-create-card.png}
## Creating
-To create a card yourself, you need to [=press the [`Create`] button on the top bar=].
+To create a card yourself, you need to {b press the {` Create} button on the top bar}.
-[image ./img/create-header.png]
+{img ./img/create-header.png}
## Viewing
-[=All=] cards (issues) can be viewed from a [url ./projects.html project]'s side menu, under 'Issues'.
+{b All} cards (issues) can be viewed from a {url project;./projects.html}'s side menu, under 'Issues'.
-[image ./img/issues-sidebar.png]
+{img ./img/issues-sidebar.png}
-Of course, they can also be viewed through [=[url ./filters.html filters]=] and a [=[url ./projects.html project]'s board=].
+Of course, they can also be viewed through {b {url filters;./filters.html}} and a {b {url project;./projects.html}'s board}.
## How to use
-By default, opening a card presents, at the top, it's [=key=] (think of it as an ID),
+By default, opening a card presents, at the top, it's {b key} (think of it as an ID),
-[image ./img/card-key.png]
+{img ./img/card-key.png}
-it's [=summary=] below it,
+it's {b summary} below it,
-[image ./img/card-summary.png]
+{img ./img/card-summary.png}
-options for adding [=attachments=], [=subtasks=], [=linking issues=] and [=adding more apps=] (think of apps like extensions),
+options for adding {b attachments}, {b subtasks}, {b linking issues} and {b adding more apps} (think of apps like extensions),
-[image ./img/card-attach-subtask.png]
+{img ./img/card-attach-subtask.png}
-following are the [=description=], [=actual attachments=], [=subtasks=], [=linked issues=], etc.,
+following are the {b description}, {b actual attachments}, {b subtasks}, {b linked issues}, etc.,
-[image ./img/desc-att-sub-link.png]
+{img ./img/desc-att-sub-link.png}
-and at the bottom you have the [=activity=], consisting of [=comments=] on the issue,
+and at the bottom you have the {b activity}, consisting of {b comments} on the issue,
-[image ./img/activity-comments.png]
+{img ./img/activity-comments.png}
-[=history=] of things that have happened to that issue,
+{b history} of things that have happened to that issue,
-[image ./img/activity-history.png]
+{img ./img/activity-history.png}
-and [=work logs=] (a bit later we talk about them in more detail).
+and {b work logs} (a bit later we talk about them in more detail).
-[image ./img/activity-work-log.png]
+{img ./img/activity-work-log.png}
### Right side
-To the right side, you have all of the different [=properties=] (some fields without a value will be hidden).
+To the right side, you have all of the different {b properties} (some fields without a value will be hidden).
-[image ./img/card-right-side.png]
+{img ./img/card-right-side.png}
-On the top right you can change [=watch options=] ([url https://www.idalko.com/jira-watch-issues/ watching an issue] means you get notified by all changes done to it), you can [=share=] the card and do [=actions=] (the three dots).
+On the top right you can change {b watch options} ({url watching an issue;https://www.idalko.com/jira-watch-issues/} means you get notified by all changes done to it), you can {b share} the card and do {b actions} (the three dots).
-[image ./img/card-top-right.png]
+{img ./img/card-top-right.png}
-[=Actions=] are things you can do to the whole card, like moving or deleting it.
+{b Actions} are things you can do to the whole card, like moving or deleting it.
-[image ./img/card-actions.png]
+{img ./img/card-actions.png}
-The most notable options are [`[url https://confluence.atlassian.com/jirasoftwarecloud/logging-work-on-issues-902499028.html Log work]`] and [`Add flag`].
+The most notable options are {` {url Log work;https://confluence.atlassian.com/jirasoftwarecloud/logging-work-on-issues-902499028.html}} and {` Add flag}.
### Work log
-In Jira, you can [=estimate how long an issue will take for it to be resolved=]. This is done through [=logging work=].
+In Jira, you can {b estimate how long an issue will take for it to be resolved}. This is done through {b logging work}.
-In the [`Log work`] screen, you'll be met with a [`Time spent`] and [`Time remaining`] fields, that you'll need to fill with the appropriate information.
+In the {` Log work} screen, you'll be met with a {` Time spent} and {` Time remaining} fields, that you'll need to fill with the appropriate information.
-[image ./img/time-tracking.png]
+{img ./img/time-tracking.png}
-The time remaining takes a [=default=] value from the [=previous time log=], so you don't need to specify it every time.
+The time remaining takes a {b default} value from the {b previous time log}, so you don't need to specify it every time.
### Issue flagging
-A [=flagged issue=] is an issue that is very important. Flagged issues are displayed in yellow to signify their needed attention.
+A {b flagged issue} is an issue that is very important. Flagged issues are displayed in yellow to signify their needed attention.
-[image ./img/flagged-card.png]
+{img ./img/flagged-card.png}
### Basic issue information
-On the bottom right you can see [=when the issue was created=] and [=when it was last updated=]. You can also access the field configuration menu from the [`Configure`] button. It won't be covered in this tutorial, you can read about it [url https://confluence.atlassian.com/adminjiracloud/changing-a-field-configuration-844500798.html here].
+On the bottom right you can see {b when the issue was created} and {b when it was last updated}. You can also access the field configuration menu from the {` Configure} button. It won't be covered in this tutorial, you can read about it {url here;https://confluence.atlassian.com/adminjiracloud/changing-a-field-configuration-844500798.html}.
-[image ./img/time-and-configure.png]
+{img ./img/time-and-configure.png}
diff --git a/src/blog/how-to-use-jira/components.du b/src/blog/how-to-use-jira/components.du
index 5f22167..71c77f4 100644
--- a/src/blog/how-to-use-jira/components.du
+++ b/src/blog/how-to-use-jira/components.du
@@ -1,50 +1,47 @@
-# Components - How to use Jira
+'def title Components - How to use Jira
+'def desc Components are yet another way to group issues together. They don't have any specific meaning like versions, their usage depends on the project's organisation.
-'define expected-reading 2 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./pages.html Pages
-'define next_link ./dashboards.html Dashboards
-[$pagination_middle]
+{pagenav 2 min;24 July 2020;03 June 2021}
+
+{pagination ./;Pages;./pages.html;Dashboards;./dashboards.html}
.contents
.numbered
-1. [url #creating-and-editing Creating and editing]
-2. [url #adding-issues Adding issues]
+1. {uhref Creating and editing}
+2. {uhref Adding issues}
-Components are [=yet another way to group issues together=]. They don't have any specific meaning like versions, their usage depends on the project's organisation.
+Components are {b yet another way to group issues together}. They don't have any specific meaning like versions, their usage depends on the project's organisation.
## Creating and editing
-Creating and editing them is done from the [=[`Components`] menu in the sidebar=].
+Creating and editing them is done from the {b {` Components} menu in the sidebar}.
-[image ./img/components-sidebar.png]
+{img ./img/components-sidebar.png}
-Creating one is done through the button on the top right (in the center if you don't have any components) by the name of [`Create component`].
+Creating one is done through the button on the top right (in the center if you don't have any components) by the name of {` Create component}.
-[image ./img/create-component-empty.png]
+{img ./img/create-component-empty.png}
-[image ./img/create-component-full.png]
+{img ./img/create-component-full.png}
Clicking on it presents you with a screen where you input it's information.
-[image ./img/create-component-page.png]
+{img ./img/create-component-page.png}
-[=A name is the only requirement=]. You can also add a [=description=], [=a lead(er) for the component=] and [=person who gets assigned to an issue by default=].
+{b A name is the only requirement}. You can also add a {b description}, {b a lead(er) for the component} and {b person who gets assigned to an issue by default}.
## Adding issues
-Adding an issue to a component can be done either [=when creating it=] or [=when viewing it=].
+Adding an issue to a component can be done either {b when creating it} or {b when viewing it}.
-[=Right under the summary=], there is a place for indicating a component, named [`Components`].
+{b Right under the summary}, there is a place for indicating a component, named {` Components}.
-[image ./img/components-create-card.png]
+{img ./img/components-create-card.png}
-When viewing an issue, you can add one from the [`Components`] field to the right (you might need to first click on [`Show more fields`]).
+When viewing an issue, you can add one from the {` Components} field to the right (you might need to first click on {` Show more fields}).
-[image ./img/show-fields.png]
+{img ./img/show-fields.png}
-[image ./img/components-field.png]
+{img ./img/components-field.png}
diff --git a/src/blog/how-to-use-jira/dashboards.du b/src/blog/how-to-use-jira/dashboards.du
index ddac024..d91a373 100644
--- a/src/blog/how-to-use-jira/dashboards.du
+++ b/src/blog/how-to-use-jira/dashboards.du
@@ -1,65 +1,63 @@
-# Dashboards - How to use Jira
+'def title Dashboards - How to use Jira
+'def desc Dashboards are a place where you can view a lot of information.
-'define expected-reading 2 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./components.html Components
-[$pagination_end]
+{pagenav 2 min;24 July 2020;03 June 2021}
+
+{pagination ./;Components;./components.html}
.contents
.numbered
-1. [url #adding-a-dashboard Adding a dashboard]
-2. [url #adding-gadgets Adding gadgets]
+1. {uhref Adding a dashboard}
+2. {uhref Adding gadgets}
-Dashboards are a [=place where you can view a lot of information=].
+Dashboards are a {b place where you can view a lot of information}.
-[image ./img/default-dashboard.png]
+{img ./img/default-dashboard.png}
-Dashboards are composed of [=gadgets=].
+Dashboards are composed of {b gadgets}.
-[image ./img/gadgets.png]
+{img ./img/gadgets.png}
-Gadgets have functionality for [=displaying certain information=], like [`Average Age Chart`] or [`Issues in progress`]. Each gadget can be setup to [=take information from one or more projects and/or saved filters=].
+Gadgets have functionality for {b displaying certain information}, like {` Average Age Chart} or {` Issues in progress}. Each gadget can be setup to {b take information from one or more projects and/or saved filters}.
## Adding a dashboard
-Dashboard can be added from the top bar, under [`Create dashboard`] in the [`Dashboards`] menu
+Dashboard can be added from the top bar, under {` Create dashboard} in the {` Dashboards} menu
-[image ./img/create-dashboard-top.png]
+{img ./img/create-dashboard-top.png}
-or, if you are already in a dashboard, from [`Create dashboard`] in the three dots menu.
+or, if you are already in a dashboard, from {` Create dashboard} in the three dots menu.
-[image ./img/create-dashboard-dots.png]
+{img ./img/create-dashboard-dots.png}
## Adding gadgets
-[=Note=]: you cannot add gadgets to the default dashboard.
+{b Note}: you cannot add gadgets to the default dashboard.
-You can add gadgets either [=through the [`Add gadget`] button in the top right=]
+You can add gadgets either {b through the {` Add gadget} button in the top right}
-[image ./img/add-gadget-top.png]
+{img ./img/add-gadget-top.png}
-or, [=if you don't have any gadets=], [=from the [`add a new gadget`] message(s)=].
+or, {b if you don't have any gadets}, {b from the {` add a new gadget} message(s)}.
-[image ./img/add-a-gadget.png]
+{img ./img/add-a-gadget.png}
-After that, you are greeted by a window that [=shows all of the avalable ones=] (you might need to [=press [`Load all gadgets`]=]).
+After that, you are greeted by a window that {b shows all of the avalable ones} (you might need to {b press {` Load all gadgets}}).
-[image ./img/load-all.png]
+{img ./img/load-all.png}
-[image ./img/add-gadget.png]
+{img ./img/add-gadget.png}
-Adding a gadget is as simple as clicking the button [`Add gadget`] next to the name of the gadget you want to add.
+Adding a gadget is as simple as clicking the button {` Add gadget} next to the name of the gadget you want to add.
-[image ./img/introduction-add.png]
+{img ./img/introduction-add.png}
-After it is added, you'll [=need to configure it=], usually a gadget [=requires atleast a filter/project=].
+After it is added, you'll {b need to configure it}, usually a gadget {b requires atleast a filter/project}.
-[image ./img/bubble.png]
+{img ./img/bubble.png}
-Options for different gadgets can be found on [=their top right corner, in the three dots menu=].
+Options for different gadgets can be found on {b their top right corner, in the three dots menu}.
-[image ./img/bubble-dots.png]
+{img ./img/bubble-dots.png}
diff --git a/src/blog/how-to-use-jira/filters.du b/src/blog/how-to-use-jira/filters.du
index f66b78c..484e121 100644
--- a/src/blog/how-to-use-jira/filters.du
+++ b/src/blog/how-to-use-jira/filters.du
@@ -1,44 +1,42 @@
-# Filters - How to use Jira
+'def title Filters - How to use Jira
+'def desc Filters work like an advanced issue search that you can save. With filters you filter issues from chosen project(s) by their properties.
-'define expected-reading 1 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define prev_link ./ Introduction
-'define next_link ./cards.html Cards
-[$pagination_second]
+{pagenav 1 min;24 July 2020;03 June 2021}
+
+{pagination ;Introduction;./;Cards;./cards.html}
.contents
.numbered
-1. [url #criteria Criteria]
-2. [url #jql JQL]
+1. {uhref Criteria}
+2. {uhref JQL}
-[=Filters work like an advanced issue search that you can save=]. With filters you filter issues from chosen project(s) by their properties (status, type, start date, etc.).
+{b Filters work like an advanced issue search that you can save}. With filters you filter issues from chosen project(s) by their properties (status, type, start date, etc.).
-Making filters is done through the [`Advanced issue search`] page, from the [`Filters`] menu.
+Making filters is done through the {` Advanced issue search} page, from the {` Filters} menu.
-[image ./img/filters-advanced-issue-search.png]
+{img ./img/filters-advanced-issue-search.png}
## Criteria
-From here you can see some criteria: [`Project`], [`Type`], [`Status`], [`Assignee`].
+From here you can see some criteria: {` Project}, {` Type}, {` Status}, {` Assignee}.
-[image ./img/criteria-advanced-issue-search.png]
+{img ./img/criteria-advanced-issue-search.png}
-Clicking on the criteria will reveal what options you can choose for it. Access to more criteria can be obtained via the [`+ More`] menu.
+Clicking on the criteria will reveal what options you can choose for it. Access to more criteria can be obtained via the {` + More} menu.
-[image ./img/plus-more-advanced-issue-search.png]
+{img ./img/plus-more-advanced-issue-search.png}
-After configuring your desired options, you can [=save the filter=] and use it later. To do so, simply click on [`Save as`] and enter a name for it.
+After configuring your desired options, you can {b save the filter} and use it later. To do so, simply click on {` Save as} and enter a name for it.
-[image ./img/save-as-advanced-issue-search.png]
-[image ./img/save-filter-filters-advanced-issue-search.png]
+{img ./img/save-as-advanced-issue-search.png}
+{img ./img/save-filter-filters-advanced-issue-search.png}
-You can view all of your filters from the conveniently named [`View all filters`] option in the [`Filters`] menu.
+You can view all of your filters from the conveniently named {` View all filters} option in the {` Filters} menu.
-[image ./img/view-all-filters-advanced-issue-search.png]
+{img ./img/view-all-filters-advanced-issue-search.png}
## JQL
-You can do [=more advanced search=] through [`JQL`] (Jira Query Language), but we won't be covering this topic. I can recommend [url https://www.atlassian.com/blog/jira-software/jql-the-most-flexible-way-to-search-jira-14 this article] on the subject.
+You can do {b more advanced search} through {` JQL} (Jira Query Language), but we won't be covering this topic. I can recommend {url this article;https://www.atlassian.com/blog/jira-software/jql-the-most-flexible-way-to-search-jira-14} on the subject.
diff --git a/src/blog/how-to-use-jira/index.du b/src/blog/how-to-use-jira/index.du
index 9ea578d..879c817 100644
--- a/src/blog/how-to-use-jira/index.du
+++ b/src/blog/how-to-use-jira/index.du
@@ -1,75 +1,74 @@
-# Introduction - How to use Jira
+'def title Introduction - How to use Jira
+'def desc Jira is one of the most used project management and issue tracking products out there. It has a lot of features and can be overwhelming to newcomers.
-'define expected-reading 19 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define next_link ./filters.html Filters
-[$pagination_start]
+{pagenav 19 min;24 July 2020;03 June 2021}
+
+{pagination ;;;Filters;./filters.html}
:contents
:numbered
-1. [url ./filters.html Filters]
+1. {url Filters;./filters.html}
.numbered
- 1. [url ./filters.html#criteria Criteria]
- 2. [url ./filters.html#jql JQL]
+ 1. {url Criteria;./filters.html#criteria}
+ 2. {url JQL;./filters.html#jql}
-2. [url ./cards.html Cards]
+2. {url Cards;./cards.html}
.numbered
- 1. [url ./cards.html#properties Properties]
- 2. [url ./cards.html#creating Creating]
- 3. [url ./cards.html#viewing Viewing]
- 4. [url ./cards.html#how-to-use How to use]
+ 1. {url Properties;./cards.html#properties}
+ 2. {url Creating;./cards.html#creating}
+ 3. {url Viewing;./cards.html#viewing}
+ 4. {url How to use;./cards.html#how-to-use}
.numbered
- 1. [url ./cards.html#right-side Right side]
- 2. [url ./cards.html#work-log Work log]
- 3. [url ./cards.html#issue-flagging Issue flagging]
- 4. [url ./cards.html#basic-issue-information Basic issue information]
+ 1. {url Right side;./cards.html#right-side}
+ 2. {url Work log;./cards.html#work-log}
+ 3. {url Issue flagging;./cards.html#issue-flagging}
+ 4. {url Basic issue information;./cards.html#basic-issue-information}
-3. [url ./projects.html Projects]
+3. {url Projects;./projects.html}
:numbered
- 1. [url ./projects.html#creating-a-project Creating a project]
- 2. [url ./projects.html#boards Boards]
+ 1. {url Creating a project;./projects.html#creating-a-project}
+ 2. {url Boards;./projects.html#boards}
.numbered
- 1. [url ./projects.html#columns Columns]
- 2. [url ./projects.html#adding-more-boards-to-a-project Adding more boards to a project]
+ 1. {url Columns;./projects.html#columns}
+ 2. {url Adding more boards to a project;./projects.html#adding-more-boards-to-a-project}
- 3. [url ./projects.html#backlog Backlog]
- 4. [url ./projects.html#add-item Add item]
+ 3. {url Backlog;./projects.html#backlog}
+ 4. {url Add item;./projects.html#add-item}
-4. [url ./kanban.html Kanban template]
+4. {url Kanban template;./kanban.html}
.numbered
- 1. [url ./kanban.html#create-board Create board]
- 2. [url ./kanban.html#backlog Backlog]
+ 1. {url Create board;./kanban.html#create-board}
+ 2. {url Backlog;./kanban.html#backlog}
-5. [url ./scrum.html Scrum template]
+5. {url Scrum template;./scrum.html}
.numbered
- 1. [url ./scrum.html#backlog Backlog]
- 2. [url ./scrum.html#boards-and-issues Boards and Issues]
- 3. [url ./scrum.html#create-board Create board]
+ 1. {url Backlog;./scrum.html#backlog}
+ 2. {url Boards and Issues;./scrum.html#boards-and-issues}
+ 3. {url Create board;./scrum.html#create-board}
-6. [url ./bug.html Bug tracking template]
+6. {url Bug tracking template;./bug.html}
-7. [url ./releases.html Releases]
+7. {url Releases;./releases.html}
-8. [url ./pages.html Pages]
+8. {url Pages;./pages.html}
-9. [url ./components.html Components]
+9. {url Components;./components.html}
.numbered
- 1. [url ./components.html#creating-and-editing Creating and editing]
- 2. [url ./components.html#adding-issues Adding issues]
+ 1. {url Creating and editing;./components.html#creating-and-editing}
+ 2. {url Adding issues;./components.html#adding-issues}
-10. [url ./dashboards.html Dashboards]
+10. {url Dashboards;./dashboards.html}
.numbered
- 1. [url ./dashboards.html#adding-a-dashboard Adding a dashboard]
- 2. [url ./dashboards.html#adding-gadgets Adding gadgets]
+ 1. {url Adding a dashboard;./dashboards.html#adding-a-dashboard}
+ 2. {url Adding gadgets;./dashboards.html#adding-gadgets}
-[url https://www.atlassian.com/software/jira Jira] is one of the most used project management and issue tracking products out there.
+{url Jira;https://www.atlassian.com/software/jira} is one of the most used project management and issue tracking products out there.
It has a lot of features that can be quite overwhelming for new comers, especially these who are new to project management software. That's why I'm writing this tutorial.
-[=Note=]: certain actions can be done only from a project administrator
+{b Note}: certain actions can be done only from a project administrator
diff --git a/src/blog/how-to-use-jira/kanban.du b/src/blog/how-to-use-jira/kanban.du
index 0a6e707..215641b 100644
--- a/src/blog/how-to-use-jira/kanban.du
+++ b/src/blog/how-to-use-jira/kanban.du
@@ -1,38 +1,35 @@
-# Kanban template - How to use Jira
+'def title Kanban template - How to use Jira
+'def desc Kanban is a way for visually organising work items (issues). Kanban consists of columns and cards, where cards are the work items and are moved from column to column.
-'define expected-reading 1 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./projects.html Projects
-'define next_link ./scrum.html Scrum template
-[$pagination_middle]
+{pagenav 1 min;24 July 2020;03 June 2021}
+
+{pagination ./;Projects;./projects.html;Scrum template;./scrum.html}
.contents
.numbered
-1. [url #create-board Create board]
-2. [url #backlog Backlog]
+1. {uhref Create board}
+2. {uhref Backlog}
-Kanban is a [=way for visually organising work items=] (issues in our case). Kanban consists of [=columns=] and [=cards=], where cards are the work items and are [=moved from one column to another=] depending on the situation. This should sound [=familiar=], because that is how [url ./projects.md Boards] work.
+Kanban is a {b way for visually organising work items} (issues in our case). Kanban consists of {b columns} and {b cards}, where cards are the work items and are {b moved from one column to another} depending on the situation. This should sound {b familiar}, because that is how {url Boards;./projects.md} work.
In a projects that uses the kanban template, boards can access directly all of the available issues.
-This tutorial focuses on the basics, but you can find a lot of information in [url https://www.atlassian.com/agile/kanban these sets of articles] from Atlassian.
+This tutorial focuses on the basics, but you can find a lot of information in {url these sets of articles;https://www.atlassian.com/agile/kanban} from Atlassian.
## Create board
-This template can be chosen when [=creating a project=]
+This template can be chosen when {b creating a project}
-[image ./img/choose-classic-template.png]
+{img ./img/choose-classic-template.png}
-and [=from the [`Create board`] screen=].
+and {b from the {` Create board} screen}.
-[image ./img/scrum-kanban-board.png]
+{img ./img/scrum-kanban-board.png}
## Backlog
-In kanban, [=the backlog is just another column in your board(s)=]. It can be removed entirely.
+In kanban, {b the backlog is just another column in your board(s)}. It can be removed entirely.
-[image ./img/backlog-kanban.png]
+{img ./img/backlog-kanban.png}
diff --git a/src/blog/how-to-use-jira/pages.du b/src/blog/how-to-use-jira/pages.du
index 5340091..9b07971 100644
--- a/src/blog/how-to-use-jira/pages.du
+++ b/src/blog/how-to-use-jira/pages.du
@@ -1,22 +1,18 @@
-# Pages - How to use Jira
+'def title Pages - How to use Jira
+'def desc Pages are a place for documents for your team. The goal is to have a centralised location where everyone in your team can share knowledge.
-'define expected-reading 1 min
-'define created 24 July 2020
-'define edited 16 September 2020
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./releases.html Releases
-'define next_link ./components.html Components
-[$pagination_middle]
+{pagenav 1 min;24 July 2020;edited 16 September 2020}
-[=Pages are a place for documents for your team=]. The goal is to have a centralised location where everyone in your team can share knowledge.
+{pagination ./;Releases;./releases.html;Components;./components.html}
-[image ./img/test-page.png]
+{b Pages are a place for documents for your team}. The goal is to have a centralised location where everyone in your team can share knowledge.
-Pages are powered by another Atlasian product, named [`Confluence`]. It is a [=subscription-based software=], but it does also offer a free 30-day trial.
+{img ./img/test-page.png}
-[=All documents=] (pages) that you write are [=organised into [`Spaces`]=]. When creating a page you can choose one of many templates or just start off with a blank one.
+Pages are powered by another Atlasian product, named {` Confluence}. It is a {b subscription-based software}, but it does also offer a free 30-day trial.
-[=Confluence won't be covered in this tutorial=]. You can read more about it [url https://www.atlassian.com/software/confluence/guides/get-started/set-up here].
+{b All documents} (pages) that you write are {b organised into {` Spaces}}. When creating a page you can choose one of many templates or just start off with a blank one.
+{b Confluence won't be covered in this tutorial}. You can read more about it {url here;https://www.atlassian.com/software/confluence/guides/get-started/set-up}.
diff --git a/src/blog/how-to-use-jira/projects.du b/src/blog/how-to-use-jira/projects.du
index fd64c86..77642a4 100644
--- a/src/blog/how-to-use-jira/projects.du
+++ b/src/blog/how-to-use-jira/projects.du
@@ -1,158 +1,155 @@
-# Projects - How to use Jira
+'def title Projects - How to use Jira
+'def desc Projects are a collection of issues with added functionality for organising them, getting statistics, etc.
-'define expected-reading 4 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./cards.html Cards
-'define next_link ./kanban.html Kanban template
-[$pagination_middle]
+{pagenav 4 min;24 July 2020;03 June 2021}
+
+{pagination ./;Cards;./cards.html;Kanban template;./kanban.html}
:contents
:numbered
-1. [url #creating-a-project Creating a project]
-2. [url #boards Boards]
+1. {uhref Creating a project}
+2. {uhref Boards}
.numbered
- 1. [url #columns Columns]
- 2. [url #adding-more-boards-to-a-project Adding more boards to a project]
+ 1. {uhref Columns}
+ 2. {uhref Adding more boards to a project}
-3. [url #backlog Backlog]
-4. [url #add-item Add item]
+3. {uhref Backlog}
+4. {uhref Add item}
-In short, [=projects are a collection of issues=] with added functionality for [=organising them, getting statistics, etc=].
+In short, {b projects are a collection of issues} with added functionality for {b organising them, getting statistics, etc}.
-[image ./img/projects.png]
+{img ./img/projects.png}
## Creating a project
-To create a project, either [=click on [`Create project`] from the menu [`Projects`] in the top bar=],
+To create a project, either {b click on {` Create project} from the menu {` Projects} in the top bar},
-[image ./img/create-project-top.png]
+{img ./img/create-project-top.png}
-or [=click on the [`Create project`] button in the [`View all projects`] page=].
+or {b click on the {` Create project} button in the {` View all projects} page}.
-[image ./img/view-all-projects-top.png]
+{img ./img/view-all-projects-top.png}
-[image ./img/create-project.png]
+{img ./img/create-project.png}
-[=Note=]: when you [=have created your account=] the first thing you'll see is the [`Create project`] page.
+{b Note}: when you {b have created your account} the first thing you'll see is the {` Create project} page.
-You'll be met by the [`Choose project type`] screen. From here choose [`Classic project`], in this tutorial the [`Next-gen project`] types [=won't be covered=].
+You'll be met by the {` Choose project type} screen. From here choose {` Classic project}, in this tutorial the {` Next-gen project} types {b won't be covered}.
-[image ./img/choose-project-type.png]
+{img ./img/choose-project-type.png}
-After that you'll need to put a [=name=] for your project, set a [=key=] (used as an ID for issues ; it is automatically generated, but you can change it if you want) and select a [=template=].
+After that you'll need to put a {b name} for your project, set a {b key} (used as an ID for issues ; it is automatically generated, but you can change it if you want) and select a {b template}.
-[image ./img/create-project-new.png]
+{img ./img/create-project-new.png}
-This tutorial covers [=only=] the three classic software templates: [=[url ./kanban.html Kanban]=], [=[url ./scrum.html Scrum]=] and [=[url ./bug.html Bug tracking]=].
+This tutorial covers {b only} the three classic software templates: {b {url Kanban;./kanban.html}}, {b {url Scrum;./scrum.html}} and {b {url Bug tracking;./bug.html}}.
-[image ./img/choose-classic-template.png]
+{img ./img/choose-classic-template.png}
-In a nutshell, [=templates=] govern how [=boards and issues should work together=]. Later in the tutorial we cover the differences between these templates.
+In a nutshell, {b templates} govern how {b boards and issues should work together}. Later in the tutorial we cover the differences between these templates.
-Projects also have [url ./releases.html Releases], [url ./pages.html Pages] and [url ./components.html Components], that are also explored.
+Projects also have {url Releases;./releases.html}, {url Pages;./pages.html} and {url Components;./components.html}, that are also explored.
## Boards
-Each project contains, amongst many other things, boards. [=Boards are a way to better organise results from [url ./filters.html filters]=]. By default every project gets a board with a filter for all of the project's issues.
+Each project contains, amongst many other things, boards. {b Boards are a way to better organise results from {url filters;./filters.html}}. By default every project gets a board with a filter for all of the project's issues.
### Columns
-[=Boards are divided into columns=] that contain the cards (issues). A card can move [=freely=] from one column to another.
+{b Boards are divided into columns} that contain the cards (issues). A card can move {b freely} from one column to another.
-[image ./img/SOD.png]
+{img ./img/SOD.png}
-To illustrate how this could be useful, let's say we have three columns: [`TO DO`], [`DOING`] and [`DONE`].
+To illustrate how this could be useful, let's say we have three columns: {` TO DO}, {` DOING} and {` DONE}.
-[image ./img/todo-doing-done.png]
+{img ./img/todo-doing-done.png}
-When you create an issue you initially put it in the [`TO DO`] column. After someone has started working on it, they put the issue in the [`DOING`] column. Finally, when the issue is resolved, it is put in the [`DONE`] column.
+When you create an issue you initially put it in the {` TO DO} column. After someone has started working on it, they put the issue in the {` DOING} column. Finally, when the issue is resolved, it is put in the {` DONE} column.
-Of course, the name, quantity and purpose of different columns [=depend on the project's organisation=].
+Of course, the name, quantity and purpose of different columns {b depend on the project's organisation}.
-Adding and removing columns can be done from the [`Columns`] tab in the [`Board settings`] menu (three dots on the top right of a board).
+Adding and removing columns can be done from the {` Columns} tab in the {` Board settings} menu (three dots on the top right of a board).
-[image ./img/board-settings.png]
+{img ./img/board-settings.png}
-[image ./img/columns-edit.png]
+{img ./img/columns-edit.png}
### Adding more boards to a project
-You can also add to a project as many [=[url ./scrum.html Scrum]=] and [=[url ./kanban.html Kanban]=] templated boards as you want.
+You can also add to a project as many {b {url Scrum;./scrum.html}} and {b {url Kanban;./kanban.html}} templated boards as you want.
-This can be done, either while in a board, from [=clicking the three dots and choosing [`Create board`]=]
+This can be done, either while in a board, from {b clicking the three dots and choosing {` Create board}}
-[image ./img/create-board.png]
+{img ./img/create-board.png}
-or [=in the sidebar, from the [`Board`] menu=].
+or {b in the sidebar, from the {` Board} menu}.
-[image ./img/sidebar-create-board.png]
+{img ./img/sidebar-create-board.png}
-After that, you are met with the [`Create a board`] window, where you can choose your template.
+After that, you are met with the {` Create a board} window, where you can choose your template.
-[image ./img/scrum-kanban-board.png]
+{img ./img/scrum-kanban-board.png}
Once you've made your choice, you will be met with three options:
-[image ./img/board-from.png]
+{img ./img/board-from.png}
:unordered
-- [=Board created with new Software project=] - creates a new project with a new board (has the name of the project).
+- {b Board created with new Software project} - creates a new project with a new board (has the name of the project).
- [image ./img/npb.png]
+ {img ./img/npb.png}
-- [=Board from existing project=] - creates a board that gets the filter from another project
+- {b Board from existing project} - creates a board that gets the filter from another project
- [image ./img/ntb.png]
+ {img ./img/ntb.png}
-- [=Board from an existing Saved Filter=] - as it says, you add to the project (indicated in the [`Location`] field) a board based on a saved filter
+- {b Board from an existing Saved Filter} - as it says, you add to the project (indicated in the {` Location} field) a board based on a saved filter
- [image ./img/ntb-filter.png]
+ {img ./img/ntb-filter.png}
## Backlog
-[=The backlog is a place for issues that outline a general task/feature=].
+{b The backlog is a place for issues that outline a general task/feature}.
-Depending on your project template, the backlog will either be a [=separate window ([url ./scrum.html Scrum])=],
+Depending on your project template, the backlog will either be a {b separate window ({url Scrum;./scrum.html})},
-[image ./img/scrum-backlog.png]
+{img ./img/scrum-backlog.png}
-[=just a column in a board ([url ./kanban.html Kanban])=],
+{b just a column in a board ({url Kanban;./kanban.html})},
-[image ./img/backlog-kanban.png]
+{img ./img/backlog-kanban.png}
-or [=nonexistent ([url ./bug.md bug tracking])=].
+or {b nonexistent ({url bug tracking;./bug.md})}.
The purpose of the backlog depends on the template and it is described in the page of each template.
## Add item
-[=You can also add some resources to the sidebar of your project=] for everyone to use. That is done through the [`Add Item`] menu.
+{b You can also add some resources to the sidebar of your project} for everyone to use. That is done through the {` Add Item} menu.
-[image ./img/add-item-kanban.png]
+{img ./img/add-item-kanban.png}
-From here you can [=add a website shortcut=], simply by putting the web address and giving it a name.
+From here you can {b add a website shortcut}, simply by putting the web address and giving it a name.
-[image ./img/add-item-to-project.png]
+{img ./img/add-item-to-project.png}
-[image ./img/add-shortcut.png]
+{img ./img/add-shortcut.png}
The name is used for showing the shortcut on the sidebar.
-[image ./img/added-site.png]
+{img ./img/added-site.png}
-You can also add a [`Bitbucket`] or [`GitHub`] repository which you can [=leave=] only as a [=shortcut=], or you can [=integrate=] it so that [=issues are transferred to Jira=].
+You can also add a {` Bitbucket} or {` GitHub} repository which you can {b leave} only as a {b shortcut}, or you can {b integrate} it so that {b issues are transferred to Jira}.
-[image ./img/test-repo.png]
+{img ./img/test-repo.png}
-[image ./img/test-repo-sidebar.png]
+{img ./img/test-repo-sidebar.png}
-[=Integration won't be covered in this tutorial=], but I can recommend [url https://www.idalko.com/jira-github-integration/ this] article for [`GitHub`] integration and [url https://www.idalko.com/jira-bitbucket-integration/ this] one for [`Bitbucket`] integration.
+{b Integration won't be covered in this tutorial}, but I can recommend {url this;https://www.idalko.com/jira-github-integration/} article for {` GitHub} integration and {url this;https://www.idalko.com/jira-bitbucket-integration/} one for {` Bitbucket} integration.
-From the [`Add Item`] menu you can also [=toggle the shortcut to [url ./pages.html Pages]=].
+From the {` Add Item} menu you can also {b toggle the shortcut to {url Pages;./pages.html}}.
diff --git a/src/blog/how-to-use-jira/releases.du b/src/blog/how-to-use-jira/releases.du
index 1642c61..f3fc54f 100644
--- a/src/blog/how-to-use-jira/releases.du
+++ b/src/blog/how-to-use-jira/releases.du
@@ -1,21 +1,18 @@
-# Releases - How to use Jira
+'def title Releases - How to use Jira
+'def desc The Releases page in a project shows versions, the ones in development and the ones that are completed.
-'define expected-reading 1 min
-'define created 24 July 2020
-'define edited 16 September 2020
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./bug.html Bug tracking template
-'define next_link ./pages.html Pages
-[$pagination_middle]
+{pagenav 1 min;24 July 2020;edited 16 September 2020}
-The [`Releases`] page in a project shows [=versions=], the ones in development and the ones that are completed.
+{pagination ./;Bug tracking template;./bug.html;Pages;./pages.html}
-[=Versions are just a big collection of issues=] and the [=goal of a released version=] is for [=all of it's issues to be resolved=]. It serves as a point in time for the development of a project.
+The {` Releases} page in a project shows {b versions}, the ones in development and the ones that are completed.
+
+{b Versions are just a big collection of issues} and the {b goal of a released version} is for {b all of it's issues to be resolved}. It serves as a point in time for the development of a project.
## Adding issues to a version
-When creating an issue, you can specify a version in the [`Fix versions`] property.
+When creating an issue, you can specify a version in the {` Fix versions} property.
-[image ./img/fix-versions.png]
+{img ./img/fix-versions.png}
diff --git a/src/blog/how-to-use-jira/scrum.du b/src/blog/how-to-use-jira/scrum.du
index dffe4ec..64a524a 100644
--- a/src/blog/how-to-use-jira/scrum.du
+++ b/src/blog/how-to-use-jira/scrum.du
@@ -1,55 +1,52 @@
-# Scrum template - How to use Jira
+'def title Scrum template - How to use Jira
+'def desc The scrum template is very similar to the kanban template with one big difference: sprints.
-'define expected-reading 2 min
-'define created 24 July 2020
-'define edited 03 June 2021
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./kanban.html Kanban template
-'define next_link ./bug.html Bug tracking template
-[$pagination_middle]
+{pagenav 2 min;24 July 2020;03 June 2021}
+
+{pagination ./;Kanban template;./kanban.html;Bug tracking template;./bug.html}
.contents
.numbered
-1. [url #backlog Backlog]
-2. [url #boards-and-issues Boards and Issues]
-3. [url #create-board Create board]
+1. {uhref Backlog}
+2. {uhref Boards and Issues}
+3. {uhref Create board}
-The scrum template is very similar to the kanban template, with one big difference: [=sprints=].
+The scrum template is very similar to the kanban template, with one big difference: {b sprints}.
-[=All issues=] are put into the [=backlog=] (which is now a [=separate page=]). From there, they are organised into [=sprints=].
+{b All issues} are put into the {b backlog} (which is now a {b separate page}). From there, they are organised into {b sprints}.
-In general [url https://www.atlassian.com/agile agile software development], a [=sprint is a small duration of time=] (one to four weeks) where the team focuses on a [=set of tasks=] and at the end everyone [=evaluates the results=] and plans the next sprint.
+In general {url agile software development;https://www.atlassian.com/agile}, a {b sprint is a small duration of time} (one to four weeks) where the team focuses on a {b set of tasks} and at the end everyone {b evaluates the results} and plans the next sprint.
-Your [=boards only work on the issues of the currently active sprint=].
+Your {b boards only work on the issues of the currently active sprint}.
## Backlog
-As we've discussed, the [=backlog=] is used for organising [=all issues=] into [=sprints=].
+As we've discussed, the {b backlog} is used for organising {b all issues} into {b sprints}.
-[image ./img/sample-scrum-backlog.png]
+{img ./img/sample-scrum-backlog.png}
-From here you can also organise [=Versions=] (refer to [url ./releases.html Releases]) and [=Epics=] (refer to [url ./cards.html Cards]). An important note is that Epics in this context don't need to have their linked issues in only one sprint.
+From here you can also organise {b Versions} (refer to {url Releases;./releases.html}) and {b Epics} (refer to {url Cards;./cards.html}). An important note is that Epics in this context don't need to have their linked issues in only one sprint.
-[image ./img/versions-and-epics.png]
+{img ./img/versions-and-epics.png}
-Creating a sprint is done from the conveniently named [`Create sprint`] button. It shows a box on top where you can either move issues from the backlog to the sprint or create entirely new issues.
+Creating a sprint is done from the conveniently named {` Create sprint} button. It shows a box on top where you can either move issues from the backlog to the sprint or create entirely new issues.
-[image ./img/sample-sprint.png]
+{img ./img/sample-sprint.png}
## Boards and Issues
-As previously mentioned, boards have access only to the issues in the active sprint. This is also reflected in the user interface. After selecting a board from the sidebar, you view it from the [`Active sprints`] page.
+As previously mentioned, boards have access only to the issues in the active sprint. This is also reflected in the user interface. After selecting a board from the sidebar, you view it from the {` Active sprints} page.
-[image ./img/active-sprints.png]
+{img ./img/active-sprints.png}
## Create board
-This template can be chosen when [=creating a project=]
+This template can be chosen when {b creating a project}
-[image ./img/choose-classic-template.png]
+{img ./img/choose-classic-template.png}
-and [=from the [`Create board`] screen=].
+and {b from the {` Create board} screen}.
-[image ./img/scrum-kanban-board.png]
+{img ./img/scrum-kanban-board.png}
diff --git a/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.du b/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.du
index 35e9fcf..744eac3 100644
--- a/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.du
+++ b/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.du
@@ -1,48 +1,48 @@
-# Icon fonts aren't evil, you just have to care
+'def title Icon fonts aren't evil, you just have to care
+'def desc Arguing that icon fonts provide useful features and using them can be done in a non-disruptive way to accessibility
-'define expected-reading 9 min
-'define created 19 July 2023
-'define edited 19 July 2023
-[$pagenav]
+# {title}
+
+{pagenav 9 min;19 July 2023;19 July 2023}
.contents
.numbered
-1. [url #the-problem-with-svgs The problem with SVGs]
-2. [url #icon-fonts Icon fonts]
+1. {uhref The problem with SVGs}
+2. {uhref Icon fonts}
.numbered
- 1. [url #text-antialiasing-unavoidable Text antialiasing: unavoidable]
- 2. [url #better-control-over-svgs-not-always-needed Better control over SVGs: not always needed]
- 3. [url #fetching-failures-and-accessible-fonts-fixable-with-care Fetching failures and accessible fonts: fixable with care]
- 4. [url #screen-reader-accessibility-almost-unavoidable Screen reader accessibility: almost unavoidable]
- 5. [url #file-size-fixable-with-care File size: fixable with care]
+ 1. {uhref Text antialiasing: unavoidable}
+ 2. {uhref Better control over SVGs: not always needed}
+ 3. {uhref Fetching failures and accessible fonts: fixable with care}
+ 4. {uhref Screen reader accessibility: almost unavoidable}
+ 5. {uhref File size: fixable with care}
-Recently I did a [url https://gitlab.com/Syndamia/syndamiadotcom/-/merge_requests/10 whole bunch of changes to the way this website works] and one of them included replacing all SVG icons with an icon font.
-While doing research, I found [url https://www.youtube.com/watch?v=9xXBYcWgCHA Seren Davies' talk] as well as [url https://www.irigoyen.dev/blog/2021/02/17/stop-using-icon-fonts/ many] [url http://technotes.iangreenleaf.com/posts/font-awesome-not-awesome.html other] [url https://www.ianfeather.co.uk/ten-reasons-we-switched-from-an-icon-font-to-svg/ posts] being against them.
+Recently I did a {url whole bunch of changes to the way this website works;https://gitlab.com/Syndamia/syndamiadotcom/-/merge_requests/10} and one of them included replacing all SVG icons with an icon font.
+While doing research, I found {url Seren Davies' talk;https://www.youtube.com/watch?v=9xXBYcWgCHA} as well as {url many;https://www.irigoyen.dev/blog/2021/02/17/stop-using-icon-fonts/} {url other;http://technotes.iangreenleaf.com/posts/font-awesome-not-awesome.html} {url posts;https://www.ianfeather.co.uk/ten-reasons-we-switched-from-an-icon-font-to-svg/} being against them.
A lot of these concerns and issues are valid and multiple times I stopped that rework, but in the end I believe, with enough care, you could make them work almost perfectly.
## The problem with SVGs
First, we have to get acquaintanced with why I wanted change: before the big rework, this website used SVG images for all icons.
-For [url https://gitlab.com/Syndamia/syndamiadotcom/-/releases/v3.0 quite a while] I've added support for an alternative light theme, but ever since the beginning icons have been an issue.
+For {url quite a while;https://gitlab.com/Syndamia/syndamiadotcom/-/releases/v3.0} I've added support for an alternative light theme, but ever since the beginning icons have been an issue.
How can you change the color, or more specifically, the internal styling of an SVG?
-You have a [url https://stackoverflow.com/questions/22252472/how-can-i-change-the-color-of-an-svg-element couple of options], if you include it with a normal [`<img>`] tag, as I was doing, you could do some [url https://stackoverflow.com/a/53336754 magic with filters] to change the exact color, though this is kinda difficult and [url https://caniuse.com/css-filters browsers support filters since somewhat recently].
+You have a {url couple of options;https://stackoverflow.com/questions/22252472/how-can-i-change-the-color-of-an-svg-element}, if you include it with a normal {` {nohtml <img>}} tag, as I was doing, you could do some {url magic with filters;https://stackoverflow.com/a/53336754} to change the exact color, though this is kinda difficult and {url browsers support filters since somewhat recently;https://caniuse.com/css-filters}.
This is a deal-breaker, because I care about older browsers and without that CSS property, icons become very difficult to see on the light theme.
-Another option is to load it with an [`\<object>`], [`\<embed>`] or [`\<iframe>`] tag, though they all [url https://stackoverflow.com/a/21503151 require JavaScript] to edit the internal styling and have [url https://vecta.io/blog/best-way-to-embed-svg a lot of problems]:
+Another option is to load it with an {` {nohtml <object>}}, {` {nohtml <embed>}} or {` {nohtml <iframe>}} tag, though they all {url require JavaScript;https://stackoverflow.com/a/21503151} to edit the internal styling and have {url a lot of problems;https://vecta.io/blog/best-way-to-embed-svg}:
.bulleted
-- [`\<object>`] [url https://vecta.io/blog/best-way-to-embed-svg#2-using-an--object--tag causes problems for search engines or the workaround forces downloading multiple files for the same image].
+- {` {nohtml <object>}} {url causes problems for search engines or the workaround forces downloading multiple files for the same image;https://vecta.io/blog/best-way-to-embed-svg#2-using-an--object--tag}.
Worst-case scenario, for every icon you would need two different HTTP requests, which significantly increases required traffic for devices on slow connections, no dice.
-- [`\<embed>`] isn't part of the HTML specification, so it could disappear from browsers at any moment and it may have very different behaviours between browsers
-- [`\<iframe>`] is [url https://stackoverflow.com/a/23178537 hard to maintain and causes problems for search engines]
+- {` {nohtml <embed>}} isn't part of the HTML specification, so it could disappear from browsers at any moment and it may have very different behaviours between browsers
+- {` {nohtml <iframe>}} is {url hard to maintain and causes problems for search engines;https://stackoverflow.com/a/23178537}
The final option is putting SVG images directly inline with the rest of the HTML.
However, this also comes with it's drawbacks:
.bulleted
- There will be no icon caching, since they'll be a part of the downloaded webpage.
-- [url https://caniuse.com/svg-html5 Browsers before ~2012 didn't support them], which is a deal-breaker since navigation-critical items wouldn't be displayed on those browsers.
+- {url Browsers before ~2012 didn't support them;https://caniuse.com/svg-html5}, which is a deal-breaker since navigation-critical items wouldn't be displayed on those browsers.
- It would also require a little bit more work to maintain, since if I wanted to change an icon I would have to go somewhere and manually insert it's contents, rather than just downloading it and replacing the existing icon.
Nevertheless, this is the best option and the one I was thinking about the most.
@@ -50,9 +50,9 @@ Nevertheless, this is the best option and the one I was thinking about the most.
## Icon fonts
The alternative is to create your own font, where you replace certain unicode symbols with your own custom graphics.
-It is [url https://caniuse.com/mdn-css_properties_font-family universally supported], changing color is as easy as changing text, adding an icon somewhere is as easy as pasting a unicode character there and the font itself can be cached.
+It is {url universally supported;https://caniuse.com/mdn-css_properties_font-family}, changing color is as easy as changing text, adding an icon somewhere is as easy as pasting a unicode character there and the font itself can be cached.
Is this too perfect to be true?
-Yes, yes it is, there are quite a lot of caveats (outlined very well, with images, on [url https://css-tricks.com/icon-fonts-vs-svg/ this post by Chris Coyier]).
+Yes, yes it is, there are quite a lot of caveats (outlined very well, with images, on {url this post by Chris Coyier;https://css-tricks.com/icon-fonts-vs-svg/}).
### Text antialiasing: unavoidable
@@ -68,24 +68,24 @@ However, I don't have any desire to do either of these, in practice my icons are
### Fetching failures and accessible fonts: fixable with care
Now, to the big problem, what happens if the browser doesn't fetch the font or if a dyslexic person changes it to something they find easier to read.
-This is one of the main issues, outlined in the aforementioned [url https://www.youtube.com/watch?v=9xXBYcWgCHA Seren Davies' talk].
+This is one of the main issues, outlined in the aforementioned {url Seren Davies' talk;https://www.youtube.com/watch?v=9xXBYcWgCHA}.
-Unicode defines certain characters as part of so-called [url https://en.wikipedia.org/wiki/Private_Use_Areas Private Use Areas] (PUA), meaning those character won't ever have a standard glyph (image) assigned to them and any font can define them freely.
+Unicode defines certain characters as part of so-called {url Private Use Areas;https://en.wikipedia.org/wiki/Private_Use_Areas} (PUA), meaning those character won't ever have a standard glyph (image) assigned to them and any font can define them freely.
The effect is that on different fonts, such a character will appear as a completely different glyph, though most don't define them at all, leaving you with a default blank square.
-This is horrible: if the font doesn't get downloaded or if you [=need=] to change it to something you can actually read, you'll get random irrelevant glyphs at best and blank squares everywhere at worst.
-To add insult to injury, icon fonts like [url https://fontawesome.com/ font-awesome] contain their icons almost exclusively in the PUA!
+This is horrible: if the font doesn't get downloaded or if you {b need} to change it to something you can actually read, you'll get random irrelevant glyphs at best and blank squares everywhere at worst.
+To add insult to injury, icon fonts like {url font-awesome;https://fontawesome.com/} contain their icons almost exclusively in the PUA!
However, this all can be fixed, at least to an extent.
The main tricks are:
:numbered
-1. [=Adding text to every clickable option=], where possible.
+1. {b Adding text to every clickable option}, where possible.
For example, I changed my theme button from an icon to "Dark theme" or "Light theme" (depending on the current theme).
.p
- Even outside this topic, having text instead of icons [url https://dev.to/megazear7/no-icon-web-design-16eb has many benefits], mainly making it easier for users to understand how to interact with the website.
+ Even outside this topic, having text instead of icons {url has many benefits;https://dev.to/megazear7/no-icon-web-design-16eb}, mainly making it easier for users to understand how to interact with the website.
-2. [=Putting important navigational and functional icons outside the PUA=] (and leaving decorational ones there).
+2. {b Putting important navigational and functional icons outside the PUA} (and leaving decorational ones there).
.p
For example, on mobile devices my sidebar is put on the top, but as to not take too much space, it is "folded" up.
@@ -99,29 +99,29 @@ The main tricks are:
But, to do the second trick, you would need your own custom font.
Thankfully, there are programs which can edit already existing ones, so you won't have to know how to make one yourself.
-I personally really like [url https://tabler-icons.io/ tabler-icons] (and more specifically, [url https://github.com/tabler/tabler-icons/releases/tag/v2.10.0 version 2.10.0]) and for the editing I use [url https://fontforge.org/en-US/ FontForge].
-So, I download the [`.ttf`] version of the font and then a (part of a) [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/FontForge-helper.ff#L37-74 FontForge script I made moves glyphs from the PUA to standard characters].
+I personally really like {url tabler-icons;https://tabler-icons.io/} (and more specifically, {url version 2.10.0;https://github.com/tabler/tabler-icons/releases/tag/v2.10.0}) and for the editing I use {url FontForge;https://fontforge.org/en-US/}.
+So, I download the {` .ttf} version of the font and then a (part of a) {url FontForge script I made moves glyphs from the PUA to standard characters;https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/FontForge-helper.ff#L37-74}.
### Screen reader accessibility: almost unavoidable
Text readers usually struggle quite a lot with Unicode characters and especially with those in the PUA.
-Generally, you have [url https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes accessibility attributes] like [url https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label aria-label], where you can explain what the given character does.
+Generally, you have {url accessibility attributes;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes} like {url aria-label;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label}, where you can explain what the given character does.
But SVGs have a title and description tags built-in, existing inside the image file itself, which is way better than adding an aria property.
### File size: fixable with care
When every icon is on a separate image, you'll download it only when needed, however with a custom font, you'll always need to download the whole font, which includes icons you don't use.
-For the aforementioned tabler-icons, the [`.ttf`] font file is 1.8 MB!
+For the aforementioned tabler-icons, the {` .ttf} font file is 1.8 MB!
That is waaaay too much, especially since the font could block rendering of the page.
But in reality, if you remove the icons that you don't use, the size difference could actually go in favor of fonts.
-In the [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/FontForge-helper.ff#L17-35 first half of my FontForge script] I select everything that isn't the 16 icons I actually use, and remove it.
+In the {url first half of my FontForge script;https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/FontForge-helper.ff#L17-35} I select everything that isn't the 16 icons I actually use, and remove it.
The same tabler-icons, but exported as (very well optimized for size) SVG files took up ~28KB in total, however the font with only those same icons was ~7KB in size.
-In reality, the most icons loaded by a page ([url /assets /assets]) totaled ~22KB in size, which is still a ~3 times reduction.
+In reality, the most icons loaded by a page ({url /assets;/assets}) totaled ~22KB in size, which is still a ~3 times reduction.
On average a page probably requests less than 7KB of icons, but still, 7KB isn't that much and once you fetch it, it get's cached and you don't have to request it ever again.
Overall, I would say size-wise, with a font containing only what you need, it could easily take up less space than the separate SVGs.
-If you still have speed issues, [url https://www.filamentgroup.com/lab/font-events.html there are always ways to load fonts progressively].
+If you still have speed issues, {url there are always ways to load fonts progressively;https://www.filamentgroup.com/lab/font-events.html}.
\n
diff --git a/src/blog/index.du b/src/blog/index.du
index cf0bf46..d282d38 100644
--- a/src/blog/index.du
+++ b/src/blog/index.du
@@ -1,113 +1,116 @@
-# Blog
+'def title Blog
+'def desc Articles detailing personal experiences or exploration of certain topics
+
+# {title}
Articles detailing personal experiences or exploration of certain topics.
\n
-#### [*2024*]
+#### {i 2024}
:defs
-; [$bg] 18 Nov &emsp; [url /blog/switchut-izgorq Суичът изгоря!]
-: [`Shallow dive`] | [`Story`] | [`Networking`] [`Switch`] [`NetworkPartner`]
+; {bg} 18 Nov &emsp; {url Суичът изгоря!;/blog/switchut-izgorq}
+: {` Shallow dive} | {` Story} | {` Networking} {` Switch} {` NetworkPartner}
-; [$gb] 06 Oct &emsp; [url /blog/the-physics-behind-a-black-hole-shader The physics behind a black hole shader]
-: [`Deep dive`] | [`Physics`] | [`General theory of relativity`] [`Celestial mechanics`] [`Gravity`] [`Black Hole`] [`Algorithm`]
+; {gb} 06 Oct &emsp; {url The physics behind a black hole shader;/blog/the-physics-behind-a-black-hole-shader}
+: {` Deep dive} | {` Physics} | {` General theory of relativity} {` Celestial mechanics} {` Gravity} {` Black Hole} {` Algorithm}
-; [$gb] 20 Feb &emsp; [url /blog/microsoft-and-foss-extinguish Microsoft and FOSS: a fire to be extinguished]
-: [`Shallow dive`] | [`Opinion`] | [`Microsoft`] [`GitHub`] [`Linux`] [`FOSS`]
+; {gb} 20 Feb &emsp; {url Microsoft and FOSS: a fire to be extinguished;/blog/microsoft-and-foss-extinguish}
+: {` Shallow dive} | {` Opinion} | {` Microsoft} {` GitHub} {` Linux} {` FOSS}
-#### [*2023*]
+#### {i 2023}
:defs
-; [$gb] 16 Dec &emsp; [url /blog/fix-qc-timeout Fix "qc timeout" kernel log error]
-: [`Linux`] | [`kernel`] | [`libata`] [`qc`] [`logs`] [`DMA`]
+; {gb} 16 Dec &emsp; {url Fix "qc timeout" kernel log error;/blog/fix-qc-timeout}
+: {` Linux} | {` kernel} | {` libata} {` qc} {` logs} {` DMA}
-; [$gb] 30 Aug &emsp; [url /blog/thinkpad-x270-my-favorite-machine ThinkPad X270 - my favorite machine]
-: [`Medium dive`] | [`Review`] | [`Lenovo`] [`ThinkPad`] [`Yoga`]
+; {gb} 30 Aug &emsp; {url ThinkPad X270 - my favorite machine;/blog/thinkpad-x270-my-favorite-machine}
+: {` Medium dive} | {` Review} | {` Lenovo} {` ThinkPad} {` Yoga}
-; [$gb] 19 Jul &emsp; [url /blog/icon-fonts-arent-evil-you-just-have-to-care Icon fonts aren't evil, you just have to care]
-: [`Shallow dive`] | [`Web development`] | [`Icon font`] [`SVG`] [`Accessibility`] [`FontForge`]
+; {gb} 19 Jul &emsp; {url Icon fonts aren't evil, you just have to care;/blog/icon-fonts-arent-evil-you-just-have-to-care}
+: {` Shallow dive} | {` Web development} | {` Icon font} {` SVG} {` Accessibility} {` FontForge}
-; [$bg] 14 Jul &emsp; [url /blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq ФМИ и висшето образование в програмистката индустрия]
-: [`Deep dive`] | [`University`] | [`FMI`] [`Education`]
+; {bg} 14 Jul &emsp; {url ФМИ и висшето образование в програмистката индустрия;/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq}
+: {` Deep dive} | {` University} | {` FMI} {` Education}
-; [$gb] 28 Jun &emsp; [url /blog/fix-network-brother-printers Fix networked Brother printers not working in Linux]
-: [`Linux`] | [`CUPS`] | [`Printers`] [`Brother`] [`Network`] [`avahi`]
+; {gb} 28 Jun &emsp; {url Fix networked Brother printers not working in Linux;/blog/fix-network-brother-printers}
+: {` Linux} | {` CUPS} | {` Printers} {` Brother} {` Network} {` avahi}
-; [$gb] 14 Jun &emsp; [url /blog/gns3-initsh-no-such-file Fix "exec /gns3/init.sh: no such file or directory"]
-: [`Linux`] | [`GNS3`] | [`Docker`] [`busybox`]
+; {gb} 14 Jun &emsp; {url Fix "exec /gns3/init.sh: no such file or directory";/blog/gns3-initsh-no-such-file}
+: {` Linux} | {` GNS3} | {` Docker} {` busybox}
-; [$gb] 07 Jun &emsp; [url /blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend Friendship ended with Funtoo, now Gentoo is my best friend]
-: [`Shallow dive`] | [`Linux`] | [`Funtoo`] [`Gentoo`] [`portage`] [`packages`] [`emerge`] [`ebuild`]
+; {gb} 07 Jun &emsp; {url Friendship ended with Funtoo, now Gentoo is my best friend;/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend}
+: {` Shallow dive} | {` Linux} | {` Funtoo} {` Gentoo} {` portage} {` packages} {` emerge} {` ebuild}
-; [$gb] 01 May &emsp; [url /blog/bash-is-weird BASH is weird]
-: [`Shallow dive`] | [`bash`] | [`Linux`] [`scripting`]
+; {gb} 01 May &emsp; {url BASH is weird;/blog/bash-is-weird}
+: {` Shallow dive} | {` bash} | {` Linux} {` scripting}
-; [$gb] 26 Apr &emsp; [url /blog/install-drivers-for-epson-scanners Install drivers for Epson scanners]
-: [`Linux`] | [`SANE`] | [`Scanners`] [`Epson`] [`epkowa`] [`iscan`]
+; {gb} 26 Apr &emsp; {url Install drivers for Epson scanners;/blog/install-drivers-for-epson-scanners}
+: {` Linux} | {` SANE} | {` Scanners} {` Epson} {` epkowa} {` iscan}
-; [$gb] 25 Apr &emsp; [url /blog/managing-apps-with-adb-without-root Managing Android apps with ADB (and without root)]
-: [`Android`] | [`ADB`] | [`Apps`] [`Linux`] [`Windows`]
+; {gb} 25 Apr &emsp; {url Managing Android apps with ADB (and without root);/blog/managing-apps-with-adb-without-root}
+: {` Android} | {` ADB} | {` Apps} {` Linux} {` Windows}
-; [$gb] 18 Apr &emsp; [url /blog/sane-explanation-of-compilers/part-1 Sane explanation of compilers: Part 1]
-: [`Deep dive`] | [`Compilers`] | [`C`] [`yacc`] [`bison`] [`math`] [`Trees`] [`Regex`] [`Grammar`] [`Languages`]
+; {gb} 18 Apr &emsp; {url Sane explanation of compilers: Part 1;/blog/sane-explanation-of-compilers/part-1}
+: {` Deep dive} | {` Compilers} | {` C} {` yacc} {` bison} {` math} {` Trees} {` Regex} {` Grammar} {` Languages}
-; [$gb] 13 Jan &emsp; [url /blog/plan9-in-linux-mouse-menus Plan 9 in Linux: Mouse menus]
-: [`Medium dive`] | [`Linux`] | [`Plan 9`] [`mouse`] [`bash`] [`script`] [`X11`] [`openbox`] [`jgmenu`] [`plumber`]
+; {gb} 13 Jan &emsp; {url Plan 9 in Linux: Mouse menus;/blog/plan9-in-linux-mouse-menus}
+: {` Medium dive} | {` Linux} | {` Plan 9} {` mouse} {` bash} {` script} {` X11} {` openbox} {` jgmenu} {` plumber}
-; [$gb] 01 Jan &emsp; [url /blog/virt-manager-freeze-on-browse virt-manager freezing up when clicking Browse in any window]
-: [`Linux`] | [`virt-manager`] | [`QEMU/KVM`] [`libvirt`] [`Linux`] [`GTK`]
+; {gb} 01 Jan &emsp; {url virt-manager freezing up when clicking Browse in any window;/blog/virt-manager-freeze-on-browse}
+: {` Linux} | {` virt-manager} | {` QEMU/KVM} {` libvirt} {` Linux} {` GTK}
-#### [*2022*]
+#### {i 2022}
:defs
-; [$gb] 23 Dec &emsp; [url /blog/2.6-years-of-web-design 2.6 years of web design]
-: [`Shallow dive`] | [`Web design`]
+; {gb} 23 Dec &emsp; {url 2.6 years of web design;/blog/2.6-years-of-web-design}
+: {` Shallow dive} | {` Web design}
-; [$gb] 13 Dec &emsp; [url /blog/when-a-language-forces-simpler-thinking When a language forces simpler thinking]
-: [`Shallow dive`] | [`Common Lisp`] | [`Advent of Code`]
+; {gb} 13 Dec &emsp; {url When a language forces simpler thinking;/blog/when-a-language-forces-simpler-thinking}
+: {` Shallow dive} | {` Common Lisp} | {` Advent of Code}
-; [$gb] 04 Dec &emsp; [url /blog/taming-the-fun-too Taming The Fun-too]
-: [`Story`] | [`Funtoo`] | [`Linux`] [`Gentoo`] [`packages`]
+; {gb} 04 Dec &emsp; {url Taming The Fun-too;/blog/taming-the-fun-too}
+: {` Story} | {` Funtoo} | {` Linux} {` Gentoo} {` packages}
-; [$gb] 01 Nov &emsp; [url /blog/turn-off-notifications-windows How to turn off notifications on Windows]
-: [`Windows 10`] | [`Settings`] | [`Notifications`]
+; {gb} 01 Nov &emsp; {url How to turn off notifications on Windows;/blog/turn-off-notifications-windows}
+: {` Windows 10} | {` Settings} | {` Notifications}
-; [$gb] 01 Nov &emsp; [url /blog/disable-sticky-keys-popup How to disable Sticky Keys prompt]
-: [`Windows`] | [`Settings`] | [`Sticky Keys`]
+; {gb} 01 Nov &emsp; {url How to disable Sticky Keys prompt;/blog/disable-sticky-keys-popup}
+: {` Windows} | {` Settings} | {` Sticky Keys}
-; [$gb] 26 Oct &emsp; [url /blog/remove-weather-widget How to remove Windows Weather Widget]
-: [`Windows 10`] | [`Settings`] | [`Taskbar`] [`Weather Widget`]
+; {gb} 26 Oct &emsp; {url How to remove Windows Weather Widget;/blog/remove-weather-widget}
+: {` Windows 10} | {` Settings} | {` Taskbar} {` Weather Widget}
-; [$gb] 04 Oct &emsp; [url /blog/windows-run-dialog Windows Run dialog]
-: [`Windows`] | [`Commands`] | [`Run`] [`Settings`]
+; {gb} 04 Oct &emsp; {url Windows Run dialog;/blog/windows-run-dialog}
+: {` Windows} | {` Commands} | {` Run} {` Settings}
-; [$gb] 03 Oct &emsp; [url /blog/export-skype How to export Skype data]
-: [`Skype`] | [`Export`] | [`Archive`] [`skype-parser`]
+; {gb} 03 Oct &emsp; {url How to export Skype data;/blog/export-skype}
+: {` Skype} | {` Export} | {` Archive} {` skype-parser}
-; [$gb] 16 Sep &emsp; [url /blog/how-to-encrypt-email How to encrypt email]
-: [`All`] | [`Email`] | [`PGP`] [`S/MIME`] [`Email Client`] [`Gmail`] [`Outlook`] [`Protonmail`]
+; {gb} 16 Sep &emsp; {url How to encrypt email;/blog/how-to-encrypt-email}
+: {` All} | {` Email} | {` PGP} {` S/MIME} {` Email Client} {` Gmail} {` Outlook} {` Protonmail}
-; [$gb] 10 Sep &emsp; [url /blog/encrypted-email Encrypted email]
-: [`Medium dive`] | [`Email`] | [`Encryption`] [`Security`] [`PGP`] [`S/MIME`] [`Protonmail`] [`Tutanota`]
+; {gb} 10 Sep &emsp; {url Encrypted email;/blog/encrypted-email}
+: {` Medium dive} | {` Email} | {` Encryption} {` Security} {` PGP} {` S/MIME} {` Protonmail} {` Tutanota}
-; [$gb] 30 Jul &emsp; [url /blog/fix-no-frame-buffer-plan9 Fix "No frame buffer" error in <span class="no-wrap">Plan 9</span>]
-: [`Plan 9`] | [`Configuration`] | [`QEMU/KVM`] [`Linux`] [`monitor`]
+; {gb} 30 Jul &emsp; {url Fix "No frame buffer" error in <span class="no-wrap">Plan 9</span>;/blog/fix-no-frame-buffer-plan9}
+: {` Plan 9} | {` Configuration} | {` QEMU/KVM} {` Linux} {` monitor}
-; [$gb] 30 Jul &emsp; [url /blog/install-plan9-with-virt-manager Install <span class="no-wrap">Plan 9</span> with virt-manager]
-: [`Plan 9`] | [`Installation`] | [`Setup`] [`QEMU/KVM`] [`virt-manager`] [`Linux`]
+; {gb} 30 Jul &emsp; {url Install <span class="no-wrap">Plan 9</span> with virt-manager;/blog/install-plan9-with-virt-manager}
+: {` Plan 9} | {` Installation} | {` Setup} {` QEMU/KVM} {` virt-manager} {` Linux}
-#### [*2020*]
+#### {i 2020}
:defs
-; [$gb] 24 Jul &emsp; [url /blog/how-to-use-jira How to use Jira]
-: [`Project Management`] | [`Jira`] | [`Agile`] [`Issue tracking`] [`Bug tracking`] [`Kanban`] [`Atlassian`]
+; {gb} 24 Jul &emsp; {url How to use Jira;/blog/how-to-use-jira}
+: {` Project Management} | {` Jira} | {` Agile} {` Issue tracking} {` Bug tracking} {` Kanban} {` Atlassian}
-; [$gb] 21 May &emsp; [url /blog/connect-to-mysql-in-dotnet-ef Connect to Mysql in .NET and Entity Framework]
-: [`ASP.Net`] | [`MySQL`] | [`Entity Framework`] [`Pomelo`]
+; {gb} 21 May &emsp; {url Connect to Mysql in .NET and Entity Framework;/blog/connect-to-mysql-in-dotnet-ef}
+: {` ASP.Net} | {` MySQL} | {` Entity Framework} {` Pomelo}
-; [$gb] 20 May &emsp; [url /blog/mundus-first-shot-at-gamedev Mundus: My first shot at game development]
-: [`Deep dive`] | [`Gamedev`] | [`2D`] [`Sandbox`] [`Crafting`] [`Building`] [`Fighting`] [`GtkSharp 2.0`] [`C#`]
+; {gb} 20 May &emsp; {url Mundus: My first shot at game development;/blog/mundus-first-shot-at-gamedev}
+: {` Deep dive} | {` Gamedev} | {` 2D} {` Sandbox} {` Crafting} {` Building} {` Fighting} {` GtkSharp 2.0} {` C#}
diff --git a/src/blog/install-drivers-for-epson-scanners/index.du b/src/blog/install-drivers-for-epson-scanners/index.du
index d6f6486..0d3c5ec 100644
--- a/src/blog/install-drivers-for-epson-scanners/index.du
+++ b/src/blog/install-drivers-for-epson-scanners/index.du
@@ -1,27 +1,23 @@
-# Install drivers for Epson scanners
+'def title Install drivers for Epson scanners
+'def desc First, make sure you have SANE installed on your machine. Second look through SANE project website, most scanners are supported out of the box, but about 15% of them either aren't supported or are untested.
-'define expected-reading 3 min
-'define created 26 April 2023
-'define edited 26 April 2023
-[$pagenav]
+# {title}
-'footnote gentoo-sane On Gentoo the package is [`sane-backends`], as per the [url https://wiki.gentoo.org/wiki/SANE wiki].
+{pagenav 3 min;26 April 2023;26 April 2023}
Sometimes your Epson scanner might work out of the box, and sometimes it might not.
-First, make sure you have [url http://sane-project.org/ SANE] installed on your machine[$gentoo-sane].
-Second look through [url http://www.sane-project.org/sane-mfgs.html#Z-EPSON the website], most scanners are supported out of the box, but about 15% of them either aren't supported or are untested.
+First, make sure you have {url SANE;http://sane-project.org/} installed on your machine{fn On Gentoo the package is {` sane-backends}, as per the {url wiki;https://wiki.gentoo.org/wiki/SANE}.}.
+Second look through {url the website;http://www.sane-project.org/sane-mfgs.html#Z-EPSON}, most scanners are supported out of the box, but about 15% of them either aren't supported or are untested.
## Complete or Good
-'footnote openrc-sane For OpenRC: [`rc-service saned status`]
-
If your scanner falls into the first category, labeled "Complete" or "Good", you probably have an issue with SANE.
-Make sure the [`saned`] service is running without errors[$openrc-sane]:
+Make sure the {` saned} service is running without errors{fn For OpenRC: {` rc-service saned status}}:
```bash
systemctl status saned.service
-and make sure the [url http://www.sane-project.org/man/sane-epson2.5.html sane-epson2] (or [url http://www.sane-project.org/man/sane-epson.5.html sane-epson]) back-end is enabled, you should have [`epson2`] (or [`epson`]) without a leading [`#`] inside [`/etc/sane.d/dll.conf`].
+and make sure the {url sane-epson2;http://www.sane-project.org/man/sane-epson2.5.html} (or {url sane-epson;http://www.sane-project.org/man/sane-epson.5.html}) back-end is enabled, you should have {` epson2} (or {` epson}) without a leading {` #} inside {` /etc/sane.d/dll.conf}.
## epkowa plus non-free interpreter
@@ -30,15 +26,15 @@ If it's unsupported and there is a note
.quote supported by the epkowa backend plus non-free interpreter
you can still make it work.
-You'll have to get the [=non-free=] (free as in [url https://en.wikipedia.org/wiki/Free_software_movement publicly available source code], you don't have to pay for anything) Epson Scan 2 software.
+You'll have to get the {b non-free} (free as in {url publicly available source code;https://en.wikipedia.org/wiki/Free_software_movement}, you don't have to pay for anything) Epson Scan 2 software.
-It can be downloaded from [url https://support.epson.net/linux/en/epsonscan2.php the support site] as a [`deb`] or [`rpm`] package.
-If your system doesn't natively work with any of those (i.e. it isn't listed under "Distribution" and isn't some sort of derivative of those), you can still try the [`rpm`] package.
+It can be downloaded from {url the support site;https://support.epson.net/linux/en/epsonscan2.php} as a {` deb} or {` rpm} package.
+If your system doesn't natively work with any of those (i.e. it isn't listed under "Distribution" and isn't some sort of derivative of those), you can still try the {` rpm} package.
:ordered
-1. Install [`rpm`] with your package manager
+1. Install {` rpm} with your package manager
-2. Download the 32 or 64 bit [=[ rpm ]=] package
+2. Download the 32 or 64 bit {b [ rpm ]} package
3. Extract it
@@ -51,12 +47,14 @@ tar -xf epsonscan2-bundle-SOMETHING.rpm.tar.gz
sudo rpm -Uvh --nodeps ./epsonscan2-bundle-SOMETHING.rpm/core/epsonscan2-SOMETHING.rpm ./epsonscan2-bundle-SOMETHING.rpm/plugins/epsonscan2-non-free-plugin-SOMETHING.rpm
-Alternatively, you can install the [`deb`] package with [`dpkg`] or build and install it from [url https://download.ebz.epson.net/man/linux/epsonscan2_e.html#sec5-1-4 source] (source file is available at the bottom of the [url https://support.epson.net/linux/en/epsonscan2.php support site]).
+Alternatively, you can install the {` deb} package with {` dpkg} or build and install it from {url source;https://download.ebz.epson.net/man/linux/epsonscan2_e.html#sec5-1-4} (source file is available at the bottom of the {url support site;https://support.epson.net/linux/en/epsonscan2.php}).
-'footnote gentoo-epkowa Surprisingly enough, on my Gentoo installation everything works fine without the package. Either something else is helping me or [url http://www.catb.org/jargon/html/magic-story.html something is in the "more magic" position]...
+'footnote gentoo-epkowa Surprisingly enough, on my Gentoo installation everything works fine without the package. Either something else is helping me or {url something is in the "more magic" position;http://www.catb.org/jargon/html/magic-story.html}...
-You will need[$gentoo-epkowa] to install [`iscan`], which usually provides the aforementioned [`epkowa`] backend.
-Also make sure you have [`epkowa`] inside [`/etc/sane.d/dll.conf`] without a leading [`#`].
+You will need{gentoo-epkowa} to install {` iscan}, which usually provides the aforementioned {` epkowa} backend.
+Also make sure you have {` epkowa} inside {` /etc/sane.d/dll.conf} without a leading {` #}.
Finally, only for the very first time after connecting your powered-on scanner, start "Epson Scan 2", select it and press "Next".
The drivers should automatically be installed and you can close the window and use your own scanning software of choice afterwards.
+
+{footnotes}
diff --git a/src/blog/install-plan9-with-virt-manager/index.du b/src/blog/install-plan9-with-virt-manager/index.du
index c60eb31..1160808 100644
--- a/src/blog/install-plan9-with-virt-manager/index.du
+++ b/src/blog/install-plan9-with-virt-manager/index.du
@@ -1,33 +1,33 @@
-# Install Plan 9 with virt-manager
+'def title Install Plan 9 with virt-manager
+'def desc Installing Plan 9 isn't difficult, but using virt-manager brings certain complications.
-'define expected-reading 4 min
-'define created 30 July 2022
-'define edited 30 July 2022
-[$pagenav]
+# {title}
+
+{pagenav 4 min;30 July 2022;30 July 2022}
.contents
.numbered
-1. [url #creating-the-virtual-machine Creating the virtual machine]
-2. [url #installing-plan-9-itself Installing Plan 9 itself]
+1. {uhref Creating the virtual machine}
+2. {uhref Installing Plan 9 itself}
-Installing [url https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs Plan 9 by Bell Labs] with [`qemu`] itself isn't difficult and there are [url https://9p.io/wiki/plan9/Installing_Plan_9_on_Qemu/ official instructions]. However, when using [`virt-manager`], there are certain uncertainties that might worry a first-timer and certain issues that arise.
+Installing {url Plan 9 by Bell Labs;https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs} with {` qemu} itself isn't difficult and there are {url official instructions;https://9p.io/wiki/plan9/Installing_Plan_9_on_Qemu/}. However, when using {` virt-manager}, there are certain uncertainties that might worry a first-timer and certain issues that arise.
## Creating the virtual machine
-We'll be installing Plan 9 with a CD (ISO) image. You can download the latest version (compiled every night) from [url https://9p.io/plan9/download.html here]. For a compressed version and checksums, refer to [url https://9p.io/wiki/plan9/Download/index.html this page].
+We'll be installing Plan 9 with a CD (ISO) image. You can download the latest version (compiled every night) from {url here;https://9p.io/plan9/download.html}. For a compressed version and checksums, refer to {url this page;https://9p.io/wiki/plan9/Download/index.html}.
:ordered
-1. Press the [*"Create a new virtual machine"*] and select [*"Local install media (ISO image or CDROM)"*]
+1. Press the {i "Create a new virtual machine"} and select {i "Local install media (ISO image or CDROM)"}
-2. For the install media select the extracted [`.iso`] CD image of Plan 9 and for operating system chose [*"Generic or unknown OS (generic)"*]
+2. For the install media select the extracted {` .iso} CD image of Plan 9 and for operating system chose {i "Generic or unknown OS (generic)"}
3. For memory select 512 MiB (the default 1024 MiB is also fine) and 1 CPU
.unordered
- - Plan 9 is stupid lightweight and according to [url https://9p.io/wiki/plan9/Installation_instructions/index.html the installation instructions] you need 16-32 MB of memory, but I still prefer to give it a little more, just in case I decide to do something extreme.
+ - Plan 9 is stupid lightweight and according to {url the installation instructions;https://9p.io/wiki/plan9/Installation_instructions/index.html} you need 16-32 MB of memory, but I still prefer to give it a little more, just in case I decide to do something extreme.
- You can also increase these values as much as you like, Plan 9 should be able to handle the more resources
-4. If you plan to only test the OS out, choose [*"Create a disk image for the virtual machine"*] and enter 2 GiB of size. If you plan more serious use, you might want to follow [url https://9p.io/wiki/plan9/Installing_Plan_9_on_Qemu/ the qemu instructions] and create a larger disk in the [`.raw`] format.
+4. If you plan to only test the OS out, choose {i "Create a disk image for the virtual machine"} and enter 2 GiB of size. If you plan more serious use, you might want to follow {url the qemu instructions;https://9p.io/wiki/plan9/Installing_Plan_9_on_Qemu/} and create a larger disk in the {` .raw} format.
5. Finally click finish.
@@ -35,57 +35,57 @@ We'll be installing Plan 9 with a CD (ISO) image. You can download the latest ve
## Installing Plan 9 itself
If everything worked correctly, on boot you should see the screen in step 1.
-From here on out, it's dead simple, and I even recommend just going through [url https://www.youtube.com/watch?v=NNWFTq0ZwLE Hatty Hacker's "Basic Plan 9 Installation" YouTube video].
+From here on out, it's dead simple, and I even recommend just going through {url Hatty Hacker's "Basic Plan 9 Installation" YouTube video;https://www.youtube.com/watch?v=NNWFTq0ZwLE}.
I'll show a more abridged version of what you need to do.
:ordered
1. On the boot screen press 1 and enter
- [image ./img/boot-screen.png]
+ {img ./img/boot-screen.png}
2. On the questions "use DMA for ide drive" and "mouseport is" press enter
-3. On "vgasize" press enter, or set up a higher (standard) resolution with 24 colors. Examples: [`1920x1080x24`], [`1280x720x24`]
+3. On "vgasize" press enter, or set up a higher (standard) resolution with 24 colors. Examples: {` 1920x1080x24}, {` 1280x720x24}
.unordered
- - A very incomplete list can be found [url https://9p.io/wiki/plan9/setting_the_right_monitor_size/index.html here]
+ - A very incomplete list can be found {url here;https://9p.io/wiki/plan9/setting_the_right_monitor_size/index.html}
-4. [=Very important!=] On "monitor" enter [`vesa`]. [`xga`] (or [`vga`]) will work during installation but seem to break when booting the installed OS.
+4. {b Very important!} On "monitor" enter {` vesa}. {` xga} (or {` vga}) will work during installation but seem to break when booting the installed OS.
.unordered
- - If you mistakenly leave it at [`xga`], refer to [url /blog/fix-no-frame-buffer-plan9 this tutorial].
+ - If you mistakenly leave it at {` xga}, refer to {url this tutorial;/blog/fix-no-frame-buffer-plan9}.
From here on out, you press enter at most of the prompts. The following list enumerates all cases where you need to do something else than press enter.
:ordered
-1. On "Disk partiton" question, enter [`sdC0`] (the option that says Hard Disk on it)
+1. On "Disk partiton" question, enter {` sdC0} (the option that says Hard Disk on it)
- [image ./img/partdisk-partition.png]
+ {img ./img/partdisk-partition.png}
-2. On "Install mbr" question, enter [`y`]
+2. On "Install mbr" question, enter {` y}
- [image ./img/partdisk-mbr.png]
+ {img ./img/partdisk-mbr.png}
-3. When you get ">>>" before the cursor, press w, then enter, then q and finally enter. This should happen twice, when in [`disk/fdisk`] and [`disk/prep`]
+3. When you get ">>>" before the cursor, press w, then enter, then q and finally enter. This should happen twice, when in {` disk/fdisk} and {` disk/prep}
- [image ./img/partdisk-fdisk.png]
+ {img ./img/partdisk-fdisk.png}
- [image ./img/prepdisk-prep.png]
+ {img ./img/prepdisk-prep.png}
-4. On "Distribution disk" type out the one that ends with [`data`] (and potentially has [`cdrom`] besides it). This is most commonly [`/dev/sdC1/data`]
+4. On "Distribution disk" type out the one that ends with {` data} (and potentially has {` cdrom} besides it). This is most commonly {` /dev/sdC1/data}
- [image ./img/mountdist-distribution-disk.png]
+ {img ./img/mountdist-distribution-disk.png}
-5. When you get "/%" before cursor (during mountdisk task) just enter [`exit`]
+5. When you get "/%" before cursor (during mountdisk task) just enter {` exit}
- [image ./img/mountdist-browse.png]
+ {img ./img/mountdist-browse.png}
-6. On "Enable boot method" enter [`plan9`]
+6. On "Enable boot method" enter {` plan9}
- [image ./img/bootsetup-boot-method.png]
+ {img ./img/bootsetup-boot-method.png}
After finishing the installation and seeing the message "Feel free to shutdown your computer", Force Off the virtual machine and then power it on again.
-On boot, on the first prompt press enter, and on the second enter [`glenda`]. Enjoy Plan 9!
+On boot, on the first prompt press enter, and on the second enter {` glenda}. Enjoy Plan 9!
diff --git a/src/blog/making-sense-of-android-root/index.du b/src/blog/making-sense-of-android-root/index.du
new file mode 100644
index 0000000..c34ca1f
--- /dev/null
+++ b/src/blog/making-sense-of-android-root/index.du
@@ -0,0 +1,69 @@
+# Making sense of Android root
+
+'define expected-reading ? min
+'define created ?
+'define edited ?
+[$pagenav]
+
+## Revision on Android rooting
+
+## Root solutions
+
+### Magisk
+
+The init process starts the system, it launches zygote processes.
+The entire point is that root level access is extremely restricted, init removes its own access after booting and zygote never allows it to begin with.
+Of course, certain stuff need root access, but this is effectively determined at boot and in your boot image.
+
+In essence, magisk inserts itself in init, so that a special Magisk process is launched, which has full privileges, and everything else is then resumed.
+This is why you need to patch/flash boot.img, that is where the instruction for init are located.
+
+### KernelSU
+
+It extends the linux kernel with additional features.
+Instead of creating a new process, everything works as normal, except that when apps launch syscalls to the kernel, something else could happen than normal.
+
+You still need to patch/flash boot.img, since that is where the kernel resides, but in general, kernelsu is better hidden/hideable and more powerful.
+
+## Modules
+
+### Zygisk
+
+In Android, all system and user processes (with the same ABI) are started by the "Zygote" process.
+zygisk (zygote - magisk) is inserted in the zygote process, which then allows you to fully control how new processes are handled.
+You can force them to execute custom code, you can change file access, etc.
+
+### SuSFS
+
+Hides paths on the filesystem level at the kernel level.
+
+### XPosed
+
+Allows you to insert ROM-level modules, without flashing a new ROM.
+So, changes which you'll normally need to make at the Android source-code level, which will be then compiled into a new ROM (version), can be made in-place without all that.
+
+## Google Play Integrity
+
+To increase security, google implemented play integrity: a series of checks which happen on your device, which allows apps to verify whether
+you device has been tampered with in any way.
+The app requests an "integrity token", Google Play Services (not Android itself!) evaluates the device state, returns an encrypted token with the
+resultant device status and then the app (should) sends it back to the servers for decryption and decision making.
+
+### Basic Integrity
+
+This checks for properties on your device.
+As you can imagine, it is not too difficult to circumvent, so every time it checks for bootloader unlock, for example, it returns false.
+
+### Device Integrity
+
+This method is harder to pass and uses device fingerprinting.
+The device and user interactions are monitored and a unique ID is created.
+This is much harder to fix, and the solution is to essentially just use a working fingerprint.
+And to pass arbitrary fingerprints you need root.
+
+### Strong Integrity
+
+This creates checks using your CPU's trusted execution environment.
+This environment knows something is up the moment you unlock your bootloader, so there is no way to spoof the check.
+Our only saving grace is that most devices do not support this feature, so there are modules which trick the system into thinking the device is older and to pass the check without really doing it.
+
diff --git a/src/blog/managing-apps-with-adb-without-root/index.du b/src/blog/managing-apps-with-adb-without-root/index.du
index 3dd9ae1..b4b0fd9 100644
--- a/src/blog/managing-apps-with-adb-without-root/index.du
+++ b/src/blog/managing-apps-with-adb-without-root/index.du
@@ -1,38 +1,38 @@
-# Managing apps with ADB (and without root)
+'def title Managing apps with ADB (and without root)
+'def desc Often new phones come with a lot of bloatware, which usually cannot be uninstalled from within the phone. This could be circumvented by rooting your device, but a better solution is using the Android Debug Bridge.
-'define expected-reading 8 min
-'define created 25 February 2023
-'define edited 25 February 2023
-[$pagenav]
+# {title}
+
+{pagenav 8 min;25 February 2023;25 February 2023}
.contents
.numbered
-1. [url #installing Installing]
-2. [url #opening-a-shell-and-connecting-to-your-device Opening a shell and connecting to your device]
-3. [url #managing-applications Managing applications]
-4. [url #what-to-remove What to remove]
+1. {uhref Installing}
+2. {uhref Opening a shell and connecting to your device}
+3. {uhref Managing applications}
+4. {uhref What to remove}
Often new phones, especially Samsung ones, come with a whole lot of bloatware, which usually cannot be uninstalled from within the phone.
-This could be circumvated by rooting your phone, essentially gaining full administrative control over the device, however this process can be somewhat involved and could [url https://www.xda-developers.com/samsung-galaxy-z-fold-3-unlock-bootloader-broken-camera/ cause issues].
+This could be circumvated by rooting your phone, essentially gaining full administrative control over the device, however this process can be somewhat involved and could {url cause issues;https://www.xda-developers.com/samsung-galaxy-z-fold-3-unlock-bootloader-broken-camera/}.
A better solution is using the Android Debug Bridge (ADB), a developer tool with which you can more fluently control your device.
Of course, you still won't get full control, but it is as close as it gets, without requiring any permanent and involved configurations.
-If you're having trouble, [url https://www.xda-developers.com/install-adb-windows-macos-linux/ XDA's article], as well as [url https://www.maketecheasier.com/uninstall-system-apps-without-root-android/ these] [url https://www.maketecheasier.com/get-started-with-android-debug-bridge-adb/ maketecheasier] [url https://www.maketecheasier.com/enable-developer-options-in-android-42/ articles] go into more detail and show pictures.
+If you're having trouble, {url XDA's article;https://www.xda-developers.com/install-adb-windows-macos-linux/}, as well as {url these;https://www.maketecheasier.com/uninstall-system-apps-without-root-android/} {url maketecheasier;https://www.maketecheasier.com/get-started-with-android-debug-bridge-adb/} {url articles;https://www.maketecheasier.com/enable-developer-options-in-android-42/} go into more detail and show pictures.
## Installing
Windows:
.numbered
-1. Download the official platform tools from [url https://dl.google.com/android/repository/platform-tools-latest-windows.zip here]
+1. Download the official platform tools from {url here;https://dl.google.com/android/repository/platform-tools-latest-windows.zip}
2. Extract the files in a folder and navigate to it
Linux (or MacOS):
.bulleted
-- With your package manager, it should be called [`android-tools`], [`android-tools-adb`] or [`android-platform-tools`]
-- Worst case scenario, download and extract it from [url https://dl.google.com/android/repository/platform-tools-latest-linux.zip here] for Linux, and [url https://dl.google.com/android/repository/platform-tools-latest-darwin.zip here] for MacOS.
+- With your package manager, it should be called {` android-tools}, {` android-tools-adb} or {` android-platform-tools}
+- Worst case scenario, download and extract it from {url here;https://dl.google.com/android/repository/platform-tools-latest-linux.zip} for Linux, and {url here;https://dl.google.com/android/repository/platform-tools-latest-darwin.zip} for MacOS.
## Opening a shell and connecting to your device
@@ -40,66 +40,66 @@ ADB is very powerfull, so by default phones don't allow you to connect to the de
First, we'll allow such a connection:
.numbered
-1. Go to [`Settings/About phone`] (depending on your Android skin, this might be located in a slightly different place)
+1. Go to {` Settings/About phone} (depending on your Android skin, this might be located in a slightly different place)
2. Tap "Build number" 7 times, until a message says you're done
-3. Navigate to the Developer options, which is often in [`Settings/Developer options`], but could also be inside the [`Settings/System`] menu
+3. Navigate to the Developer options, which is often in {` Settings/Developer options}, but could also be inside the {` Settings/System} menu
4. Enable the "USB debugging option" (if a popup appears, click OK)
ADB is a command-line only tool, so first open a terminal inside the platform-tools directory:
.bulleted
- On Window, Right-click in the directory and press "Open PowerShell window here" or "Open command window here" or "Open in Terminal" (different OS versions show a different option)
-- On Linux (and MacOS), open a terminal window and [`cd`] to the platform-tools directory
+- On Linux (and MacOS), open a terminal window and {` cd} to the platform-tools directory
Connect your phone to the computer with a USB cable, change the transfer mode to "File transfer" and in the terminal enter:
-```shell
+```sh
adb devices
On your phone you should get a poppup asking "Allow USB debugging?", press OK.
You should get a "List of devices attached", and it should have one entry (a line below it, with some number and letters and then the word "device").
-'footnote interactive-shell You could just run every command like [`adb shell COMMAND`], which wouldn't give you an interactive shell, so it is less convinient
+'footnote interactive-shell You could just run every command like {` adb shell COMMAND}, which wouldn't give you an interactive shell, so it is less convinient
-Now, we'll open a shell[$interactive-shell], a program with which to directly enter commands that the device understands:
+Now, we'll open a shell{interactive-shell}, a program with which to directly enter commands that the device understands:
-```shell
+```sh
adb shell
## Managing applications
There are 3 general commands that you would want to use:
-```shell
+```sh
pm list packages
Which prints the internal names of all applications that are installed on the device.
All of the other commands use those names (without the leading "package:", if it exists) for referring to applications.
-```shell
+```sh
pm uninstall -k --user 0 PACKAGE
Where PACKAGE is an aforementioned application name.
This command just uninstalls the app for the normal user, meaning it will be brought back on factory reset.
-```shell
+```sh
pm disable --user 0 PACKAGE
Disabled PACKAGE, so it wouldn't work but you wouldn't need to reinstall it (just enable it).
-Beware that, if it shows some sort of error (anything that isn't "Success"), you'll probably need to use [`disable-user`], rather than just [`disable`].
+Beware that, if it shows some sort of error (anything that isn't "Success"), you'll probably need to use {` disable-user}, rather than just {` disable}.
-After you're done, you can pretty much just unplug your device, but remember to [=turn back off the "USB debugging" option!=]
+After you're done, you can pretty much just unplug your device, but remember to {b turn back off the "USB debugging" option!}
## What to remove
This is a lost of commands, which remove a whole lot of arguably unnecessary apps.
-Use [=AT YOUR OWN RISK!=]
-Although they shouldn't, they might cause problems [=FOR WHICH I'M NOT RESPONSIBLE!=]
+Use {b AT YOUR OWN RISK!}
+Although they shouldn't, they might cause problems {b FOR WHICH I'M NOT RESPONSIBLE!}
:unordered
- Facebook
-```shell
+```sh
pm uninstall -k --user 0 package:com.facebook.services
pm uninstall -k --user 0 package:com.facebook.katana
pm uninstall -k --user 0 package:com.facebook.system
@@ -107,13 +107,13 @@ pm uninstall -k --user 0 package:com.facebook.appmanager
- Netflix
-```shell
+```sh
pm uninstall -k --user 0 com.netflix.partner.activation
pm uninstall -k --user 0 com.netflix.mediaclient
- Microsoft apps
-```shell
+```sh
pm uninstall -k --user 0 com.microsoft.skydrive
pm uninstall -k --user 0 com.skype.raider
pm uninstall -k --user 0 com.microsoft.office.excel
@@ -122,7 +122,7 @@ pm uninstall -k --user 0 com.microsoft.office.powerpoint
- Google apps
-```shell
+```sh
pm uninstall -k --user 0 com.google.android.googlequicksearchbox
pm uninstall -k --user 0 com.google.android.gm
pm uninstall -k --user 0 com.google.android.apps.tachyon
@@ -141,17 +141,17 @@ pm uninstall -k --user 0 com.google.android.apps.plus
- Windows 10 Phone comanion
-```shell
+```sh
pm uninstall -k --user 0 com.microsoft.appmanager
- AR Emoji
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.aremoji
- Bixby
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.bixby.agent
pm uninstall -k --user 0 com.samsung.android.bixby.es.globalaction
pm uninstall -k --user 0 com.samsung.android.bixbyvision.framework
@@ -169,7 +169,7 @@ pm uninstall -k --user 0 com.samsung.android.app.spage
- Samsung Pass/Pay
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.samsungpassautofill
pm uninstall -k --user 0 com.samsung.android.authfw
pm uninstall -k --user 0 com.samsung.android.samsungpass
@@ -178,13 +178,13 @@ pm uninstall -k --user 0 com.samsung.android.spayfw
- Samsung Kids
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.kidsinstaller
pm uninstall -k --user 0 com.samsung.android.app.camera.sticker.facearavatar.preload
- Samsung Game Launcher
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.game.gamehome
pm uninstall -k --user 0 com.enhance.gameservice
pm uninstall -k --user 0 com.samsung.android.game.gametools
@@ -192,50 +192,50 @@ pm uninstall -k --user 0 com.samsung.android.game.gos
- Galaxy Friends
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.mateagent
- Samsung Smartthings
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.easysetup
pm uninstall -k --user 0 com.samsung.android.beaconmanager
pm uninstall -k --user 0 com.samsung.android.oneconnect
- Carmode
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.drivelink.stub
- Stickers
-```shell
+```sh
pm uninstall -k --user 0 com.sec.android.mimage.avatarstickers
- Samsung Global Goals
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.sree
- Samsung Members
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.voc
- Samsung LED cover
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.app.ledbackcover
pm uninstall -k --user 0 com.sec.android.cover.ledcover
- Samsung TV
-```shell
+```sh
pm uninstall -k --user 0 com.sec.android.app.withtv
- Knox
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.knox.securefolder
pm uninstall -k --user 0 com.knox.vpn.proxyhandler
pm uninstall -k --user 0 com.samsung.knox.keychain
@@ -246,33 +246,33 @@ pm uninstall -k --user 0 com.samsung.android.knox.containercore
- Samsung DEX
-```shell
+```sh
pm uninstall -k --user 0 com.sec.android.desktopmode.uiservice
pm uninstall -k --user 0 com.samsung.desktopsystemui
pm uninstall -k --user 0 com.sec.android.app.desktoplauncher
- Samsung Browser
-```shell
+```sh
pm uninstall -k --user 0 com.sec.android.app.sbrowser
pm uninstall -k --user 0 com.samsung.android.app.sbrowseredge
- Samsung Email
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.email.provider
pm uninstall -k --user 0 com.wsomacp
- Samsung Smartthings
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.easysetup
pm uninstall -k --user 0 com.samsung.android.beaconmanager
pm uninstall -k --user 0 com.samsung.android.oneconnect
- Gear VR
-```shell
+```sh
pm uninstall -k --user 0 com.samsung.android.hmt.vrsvc
pm uninstall -k --user 0 com.samsung.android.app.vrsetupwizardstub
pm uninstall -k --user 0 com.samsung.android.hmt.vrshell
@@ -280,19 +280,19 @@ pm uninstall -k --user 0 com.google.vr.vrcore
- Printings
-```shell
+```sh
pm uninstall -k --user 0 com.android.bips
pm uninstall -k --user 0 com.google.android.printservice.recommendation
pm uninstall -k --user 0 com.android.printspooler
- Upday news
-```shell
+```sh
pm uninstall -k --user 0 de.axelspringer.yana.zeropage
- Verizon
-```shell
+```sh
pm uninstall -k --user 0 com.vcast.mediamanager
pm uninstall -k --user 0 com.samsung.vmmhux
pm uninstall -k --user 0 com.vzw.hss.myverizon
@@ -304,12 +304,12 @@ pm uninstall -k --user 0 com.vznavigator.[You_Model_Here]
- T-mobile
-```shell
+```sh
pm uninstall -k --user 0 com.mobitv.client.tmobiletvhd
pm uninstall -k --user 0 us.com.dt.iq.appsource.tmobile
\n
-More information on available package commands can be shown with [`pm help`].
-You can learn more about the adb tool from [url https://developer.android.com/studio/command-line/adb developer.android.com].
+More information on available package commands can be shown with {` pm help}.
+You can learn more about the adb tool from {url developer.android.com;https://developer.android.com/studio/command-line/adb}.
diff --git a/src/blog/microsoft-and-foss-extinguish/index.du b/src/blog/microsoft-and-foss-extinguish/index.du
index f699a64..0f99b45 100644
--- a/src/blog/microsoft-and-foss-extinguish/index.du
+++ b/src/blog/microsoft-and-foss-extinguish/index.du
@@ -1,21 +1,21 @@
-# Microsoft and FOSS: a fire to be extinguished
+'def title Microsoft and FOSS: a fire to be extinguished
+'def desc Sharing my thoughts on how Microsoft is (probably) trying to kill FOSS in the long term
-'define expected-reading 6 min
-'define created 20 February 2024
-'define edited 20 February 2024
-[$pagenav]
+# {title}
+
+{pagenav 6 min;20 February 2024;20 February 2024}
.contents
.numbered
-1. [url #githubs-embrace-and-extensions GitHub's embrace and extensions]
-2. [url #blowtorch-to-the-penguin Blowtorch to the penguin]
-3. [url #but-these-are-good-things-for-the-user But these are good things for the user]
+1. {uhref GitHub's embrace and extensions}
+2. {uhref Blowtorch to the penguin}
+3. {uhref But these are good things for the user}
.numbered
- 1. [url #the-practical-answer The practical answer]
- 2. [url #the-moral-answer The moral answer]
+ 1. {uhref The practical answer}
+ 2. {uhref The moral answer}
-A week ago [url https://devblogs.microsoft.com/commandline/introducing-sudo-for-windows/ Microsoft announced they'll be adding "sudo" to Windows].
-I'm not really knowledgeable enough to be certain what I'm saying is true, so I could be wrong, but upon hearing these news, my mind immediately jumped to the [url https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish EEE: Embrace, Extend, Extinguish].
+A week ago {url Microsoft announced they'll be adding "sudo" to Windows;https://devblogs.microsoft.com/commandline/introducing-sudo-for-windows/}.
+I'm not really knowledgeable enough to be certain what I'm saying is true, so I could be wrong, but upon hearing these news, my mind immediately jumped to the {url EEE: Embrace, Extend, Extinguish;https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish}.
As it is explained on Wikipedia, this is a very old and successful tactic, where Microsoft would enter new markets by:
@@ -31,22 +31,22 @@ Open-source by itself is primarily about publishing the source code of your proj
Now we have:
.bulleted
-- [url https://octoverse.github.com/ GitHub Octoverse], yearly reports on open-source globally, but quite often through the lens of GitHub
-- [url https://resources.github.com/newsletter/ GitHub Insider], a monthly newsletter
-- [url https://github.com/features/copilot/ GitHub Copilot], an AI developer tool
-- [url https://github.com/enterprise GitHub Enterprise], an AI developer platform
-- [url https://github.blog/ GitHub blog], mostly a set of tutorials and informational articles regarding GitHub
+- {url GitHub Octoverse;https://octoverse.github.com/}, yearly reports on open-source globally, but quite often through the lens of GitHub
+- {url GitHub Insider;https://resources.github.com/newsletter/}, a monthly newsletter
+- {url GitHub Copilot;https://github.com/features/copilot/}, an AI developer tool
+- {url GitHub Enterprise;https://github.com/enterprise}, an AI developer platform
+- {url GitHub blog;https://github.blog/}, mostly a set of tutorials and informational articles regarding GitHub
and the list just goes on.
GitHub isn't just a public place to view open-source software anymore, if you are a novice developer or you just don't care that much, it will be very easy to associate the FOSS community with the GitHub community.
Once you've started using all of those services and tools, there is no coming back, because other repository platforms focus only on repositories.
-I mean, [url https://gitlab.com/ GitLab] doesn't offer a developer forum like [url https://docs.github.com/en/discussions/collaborating-with-your-community-using-discussions/about-discussions GitHub Discussions], you won't find a [url https://sourcehut.org/ sourcehut]-branded FOSS newsletter, [url https://sourceforge.net/ SourceForge] won't allow you to add [url https://github.com/abhisheknaiidu/awesome-github-profile-readme animations, graphics, games, etc. on your profile], there isn't a [url https://codeberg.org/ codeberg] [url https://cli.github.com/ command-line repository management app], so [*obviously GitHub is where it's at for FOSS*].
+I mean, {url GitLab;https://gitlab.com/} doesn't offer a developer forum like {url GitHub Discussions;https://docs.github.com/en/discussions/collaborating-with-your-community-using-discussions/about-discussions}, you won't find a {url sourcehut;https://sourcehut.org/}-branded FOSS newsletter, {url SourceForge;https://sourceforge.net/} won't allow you to add {url animations, graphics, games, etc. on your profile;https://github.com/abhisheknaiidu/awesome-github-profile-readme}, there isn't a {url codeberg;https://codeberg.org/} {url command-line repository management app;https://cli.github.com/}, so {i obviously GitHub is where it's at for FOSS}.
-And you'll be introduced to GitHub before any of the others, thanks to the [url https://education.github.com/pack GitHub Student Developer Pack], where students can get free access to a variety of services, or to [url https://docs.github.com/en/education/manage-coursework-with-github-classroom/get-started-with-github-classroom/about-github-classroom GitHub classroom], where newer developers will probably publish their first pieces of code.
+And you'll be introduced to GitHub before any of the others, thanks to the {url GitHub Student Developer Pack;https://education.github.com/pack}, where students can get free access to a variety of services, or to {url GitHub classroom;https://docs.github.com/en/education/manage-coursework-with-github-classroom/get-started-with-github-classroom/about-github-classroom}, where newer developers will probably publish their first pieces of code.
-Why learn to use the git terminal command when [url https://desktop.github.com/ GitHub Desktop] abstract everything away in a beautiful clicky interface (as a "bonus", this will make you associate git with GitHub too), why follow [url https://news.ycombinator.com/ Hacker News] or multiple different FOSS websites, when Microsoft provides.
+Why learn to use the git terminal command when {url GitHub Desktop;https://desktop.github.com/} abstract everything away in a beautiful clicky interface (as a "bonus", this will make you associate git with GitHub too), why follow {url Hacker News;https://news.ycombinator.com/} or multiple different FOSS websites, when Microsoft provides.
Why learn anything, when Microsoft's GitHub serves it to you on a silver platter?
Well, for an increasing number of developers, I fear, the answer is: "there is no point".
@@ -54,10 +54,10 @@ Well, for an increasing number of developers, I fear, the answer is: "there is n
## Blowtorch to the penguin
Now let's talk about Microsoft's other plaything: Linux.
-Here, I feel, the tactic is even more obvious: thanks to [url https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux WSL], Linux applications look and run like any other Windows app.
-Thanks to [url https://en.wikipedia.org/wiki/Windows_Terminal Windows Terminal], Windows can't be seen as a lesser OS for developers, all benefits of having a proper, fully-fledged, UNIX-like command-line can now be found on Windows.
+Here, I feel, the tactic is even more obvious: thanks to {url WSL;https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux}, Linux applications look and run like any other Windows app.
+Thanks to {url Windows Terminal;https://en.wikipedia.org/wiki/Windows_Terminal}, Windows can't be seen as a lesser OS for developers, all benefits of having a proper, fully-fledged, UNIX-like command-line can now be found on Windows.
-I mean, they've added the sudo command for crying out loud, there is even an official [url https://en.wikipedia.org/wiki/Windows_Package_Manager Windows package manager]!
+I mean, they've added the sudo command for crying out loud, there is even an official {url Windows package manager;https://en.wikipedia.org/wiki/Windows_Package_Manager}!
For a novice or someone uninterested, you wouldn't ever have to learn how to use Linux.
You'll use Windows as you've known for your entire life, and if you need something even vaguely related to Linux, you'll just easily get it on another silver platter.
@@ -82,7 +82,7 @@ It's tempting to imagine Linux software or Linux projects turn into Windows soft
### The moral answer
-[url https://en.wikipedia.org/wiki/We_choose_to_go_to_the_Moon We do things, not because they are easy, but because they are hard].
+{url We do things, not because they are easy, but because they are hard;https://en.wikipedia.org/wiki/We_choose_to_go_to_the_Moon}.
Knowledge is the most important resource we have, everything humanity has achieved has been with the creation, expansion and distribution of knowledge.
Developers are the craftsmen of computer software and to create you need knowledge, the more you have the more you can do.
diff --git a/src/blog/mundus-first-shot-at-gamedev/basic-concepts.du b/src/blog/mundus-first-shot-at-gamedev/basic-concepts.du
index 630ed2f..4bc87f8 100644
--- a/src/blog/mundus-first-shot-at-gamedev/basic-concepts.du
+++ b/src/blog/mundus-first-shot-at-gamedev/basic-concepts.du
@@ -1,25 +1,23 @@
-# Basic Concepts - Mundus: My first shot at game development
+'def title Basic Concepts - Mundus: My first shot at game development
+'def desc A deep dive into a small GTK-based game I developed
-'define expected-reading 5 min
-'define created 21 July 2020
-'define edited 25 November 2020
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./user-interface.html User Interface
-[$pagination_end]
+{pagenav 5 min;21 July 2020;25 November 2020}
-[$due_for_rework]
+{pagination ./;User Interface;./user-interface.html}
+
+{due_for_rework}
\n
.contents
.numbered
-1. [url #tiles Tiles]
-2. [url #layers-and-superlayers Layers and superlayers]
-3. [url #inventory Inventory]
-4. [url #crafting Crafting]
-5. [url #event-logs Event logs]
+1. {uhref Tiles}
+2. {uhref Layers and superlayers}
+3. {uhref Inventory}
+4. {uhref Crafting}
+5. {uhref Event logs}
Even though the game is quite unfinished, there are still a fair bit of mechanics I've developed.
@@ -27,7 +25,7 @@ Even though the game is quite unfinished, there are still a fair bit of mechanic
The in game world (map) is composed of squares, called tiles. Everything is a type of tile. There are two main categories of tiles: items and mobs. Mobs (mobile object for short) are the creatures in the game, while items are everything else, from the tools, to the trees.
-There is only one type of mob tile and that is [`MobTiles`]. All mobs, with the exception of the player, have the same functionality and properties:
+There is only one type of mob tile and that is {` MobTiles}. All mobs, with the exception of the player, have the same functionality and properties:
:unordered
- health - if it drops to or below 0, they die
@@ -72,11 +70,11 @@ The in game world (map) is composed of superlayers. Superlayers represent each e
Each superlayer is composed of 3 layers: Structure, Mob and Ground. Each one of them contains a specific type of tiles, meaning structure tiles are only stored in "structure" layer, ground tiles only in "ground" layer and mob tiles only in "mob" layer. Even though, they are different layers, there are some rules for the interaction between them:
:unordered
-- [=Mobs cannot be on top of structures=], except if the structure is marked as "walkable"
+- {b Mobs cannot be on top of structures}, except if the structure is marked as "walkable"
-- [=Structures cannot be placed on top of mobs=]. "Walkable" structures can be placed below a mob.
+- {b Structures cannot be placed on top of mobs}. "Walkable" structures can be placed below a mob.
-- [=Structures cannot be placed on top of holes=] (empty spots in the ground layer), [=except if they are "climable"=], in which case they will be placed in the structure layer on the superlayer below. Mobs also cannot reside on top of holes (they fall to the superlayer below)
+- {b Structures cannot be placed on top of holes} (empty spots in the ground layer), {b except if they are "climable"}, in which case they will be placed in the structure layer on the superlayer below. Mobs also cannot reside on top of holes (they fall to the superlayer below)
## Inventory
diff --git a/src/blog/mundus-first-shot-at-gamedev/index.du b/src/blog/mundus-first-shot-at-gamedev/index.du
index 9c1cabf..f5656fc 100644
--- a/src/blog/mundus-first-shot-at-gamedev/index.du
+++ b/src/blog/mundus-first-shot-at-gamedev/index.du
@@ -1,48 +1,47 @@
-# Introduction - Mundus: My first shot at game development
+'def title Introduction - Mundus: My first shot at game development
+'def desc General background on Mundus
-'define expected-reading 2 min
-'define created 21 July 2020
-'define edited 25 November 2020
-[$pagenav]
+# {title}
-'define next_link ./timeline.html Timeline
-[$pagination_start]
+{pagenav 2 min;21 July 2020;25 November 2020}
-[$due_for_rework]
+{pagination ;;;Timeline;./timeline.html}
+
+{due_for_rework}
\n
:contents
:numbered
-1. [url ./timeline.html Timeline]
-2. [url ./user-interface.html User Interface]
+1. {url Timeline;./timeline.html}
+2. {url User Interface;./user-interface.html}
.numbered
- 1. [url ./user-interface.html#main-screen Main screen]
- 2. [url ./user-interface.html#create-new-game Create new game]
- 3. [url ./user-interface.html#game-window Game Window]
- 4. [url ./user-interface.html#map-menu Map menu]
- 5. [url ./user-interface.html#inventory-menu Inventory menu]
- 6. [url ./user-interface.html#crafting-menu Crafting menu]
+ 1. {url Main screen;./user-interface.html#main-screen}
+ 2. {url Create new game;./user-interface.html#create-new-game}
+ 3. {url Game Window;./user-interface.html#game-window}
+ 4. {url Map menu;./user-interface.html#map-menu}
+ 5. {url Inventory menu;./user-interface.html#inventory-menu}
+ 6. {url Crafting menu;./user-interface.html#crafting-menu}
-3. [url ./basic-concepts.html Basic Concepts]
+3. {url Basic Concepts;./basic-concepts.html}
.numbered
- 1. [url ./basic-concepts.html#tiles Tiles]
- 2. [url ./basic-concepts.html#layers-and-superlayers Layers and superlayers]
- 3. [url ./basic-concepts.html#inventory Inventory]
- 4. [url ./basic-concepts.html#crafting Crafting]
- 5. [url ./basic-concepts.html#event-logs Event logs]
+ 1. {url Tiles;./basic-concepts.html#tiles}
+ 2. {url Layers and superlayers;./basic-concepts.html#layers-and-superlayers}
+ 3. {url Inventory;./basic-concepts.html#inventory}
+ 4. {url Crafting;./basic-concepts.html#crafting}
+ 5. {url Event logs;./basic-concepts.html#event-logs}
-I have been toying with the idea of making a game ever since my first exposure to programming. The [url https://gitlab.com/Syndamia/Shower/-/tree/master/ARK%20(2015 earliest piece of code]) I ever wrote was about replicating a computer boot up sequence from the video game [url https://store.steampowered.com/app/282140/SOMA/ SOMA]. I developed it in 2015, solid 3 years before my first proper introduction to software development.
+I have been toying with the idea of making a game ever since my first exposure to programming. The {url earliest piece of code;https://gitlab.com/Syndamia/Shower/-/tree/master/ARK%20(2015}) I ever wrote was about replicating a computer boot up sequence from the video game {url SOMA;https://store.steampowered.com/app/282140/SOMA/}. I developed it in 2015, solid 3 years before my first proper introduction to software development.
Five years later, in early 2020, I had to make a project for an exam. I (initially) had about a month to complete it and the only requirements were technical: utilize a database with at least x tables, employ a specific design pattern, etc. Fairly quickly I decided upon making a "minecraftian" game: 2D sandbox where you could fight, craft, build, eat and explore.
-I called it [url https://gitlab.com/Syndamia/Mundus Mundus] and it took me around 3 months to complete and consisted of more than 2000 lines of code. Although these metrics aren't very impressive in the real world, they were a monumental achievement for me. In the beginning I planned on developing it into a fully fledged game, but that never happened.
+I called it {url Mundus;https://gitlab.com/Syndamia/Mundus} and it took me around 3 months to complete and consisted of more than 2000 lines of code. Although these metrics aren't very impressive in the real world, they were a monumental achievement for me. In the beginning I planned on developing it into a fully fledged game, but that never happened.
Nevertheless, this journey was very important to me, hence writing this multi-page article.
-[=Link to the source code=]: [url https://gitlab.com/Syndamia/Mundus GitLab]
+{b Link to the source code}: {url GitLab;https://gitlab.com/Syndamia/Mundus}
## Screenshots
@@ -52,4 +51,4 @@ Nevertheless, this journey was very important to me, hence writing this multi-pa
<img src="./img/inventory-menu.png" style="height: 100%; flex: 1;">
</div>
-[*Screenshots are made on Linux Mint Cinnamon with the Mint-Y theme*]
+{i Screenshots are made on Linux Mint Cinnamon with the Mint-Y theme}
diff --git a/src/blog/mundus-first-shot-at-gamedev/introduction.du b/src/blog/mundus-first-shot-at-gamedev/introduction.du
index 9c1cabf..f5656fc 100644
--- a/src/blog/mundus-first-shot-at-gamedev/introduction.du
+++ b/src/blog/mundus-first-shot-at-gamedev/introduction.du
@@ -1,48 +1,47 @@
-# Introduction - Mundus: My first shot at game development
+'def title Introduction - Mundus: My first shot at game development
+'def desc General background on Mundus
-'define expected-reading 2 min
-'define created 21 July 2020
-'define edited 25 November 2020
-[$pagenav]
+# {title}
-'define next_link ./timeline.html Timeline
-[$pagination_start]
+{pagenav 2 min;21 July 2020;25 November 2020}
-[$due_for_rework]
+{pagination ;;;Timeline;./timeline.html}
+
+{due_for_rework}
\n
:contents
:numbered
-1. [url ./timeline.html Timeline]
-2. [url ./user-interface.html User Interface]
+1. {url Timeline;./timeline.html}
+2. {url User Interface;./user-interface.html}
.numbered
- 1. [url ./user-interface.html#main-screen Main screen]
- 2. [url ./user-interface.html#create-new-game Create new game]
- 3. [url ./user-interface.html#game-window Game Window]
- 4. [url ./user-interface.html#map-menu Map menu]
- 5. [url ./user-interface.html#inventory-menu Inventory menu]
- 6. [url ./user-interface.html#crafting-menu Crafting menu]
+ 1. {url Main screen;./user-interface.html#main-screen}
+ 2. {url Create new game;./user-interface.html#create-new-game}
+ 3. {url Game Window;./user-interface.html#game-window}
+ 4. {url Map menu;./user-interface.html#map-menu}
+ 5. {url Inventory menu;./user-interface.html#inventory-menu}
+ 6. {url Crafting menu;./user-interface.html#crafting-menu}
-3. [url ./basic-concepts.html Basic Concepts]
+3. {url Basic Concepts;./basic-concepts.html}
.numbered
- 1. [url ./basic-concepts.html#tiles Tiles]
- 2. [url ./basic-concepts.html#layers-and-superlayers Layers and superlayers]
- 3. [url ./basic-concepts.html#inventory Inventory]
- 4. [url ./basic-concepts.html#crafting Crafting]
- 5. [url ./basic-concepts.html#event-logs Event logs]
+ 1. {url Tiles;./basic-concepts.html#tiles}
+ 2. {url Layers and superlayers;./basic-concepts.html#layers-and-superlayers}
+ 3. {url Inventory;./basic-concepts.html#inventory}
+ 4. {url Crafting;./basic-concepts.html#crafting}
+ 5. {url Event logs;./basic-concepts.html#event-logs}
-I have been toying with the idea of making a game ever since my first exposure to programming. The [url https://gitlab.com/Syndamia/Shower/-/tree/master/ARK%20(2015 earliest piece of code]) I ever wrote was about replicating a computer boot up sequence from the video game [url https://store.steampowered.com/app/282140/SOMA/ SOMA]. I developed it in 2015, solid 3 years before my first proper introduction to software development.
+I have been toying with the idea of making a game ever since my first exposure to programming. The {url earliest piece of code;https://gitlab.com/Syndamia/Shower/-/tree/master/ARK%20(2015}) I ever wrote was about replicating a computer boot up sequence from the video game {url SOMA;https://store.steampowered.com/app/282140/SOMA/}. I developed it in 2015, solid 3 years before my first proper introduction to software development.
Five years later, in early 2020, I had to make a project for an exam. I (initially) had about a month to complete it and the only requirements were technical: utilize a database with at least x tables, employ a specific design pattern, etc. Fairly quickly I decided upon making a "minecraftian" game: 2D sandbox where you could fight, craft, build, eat and explore.
-I called it [url https://gitlab.com/Syndamia/Mundus Mundus] and it took me around 3 months to complete and consisted of more than 2000 lines of code. Although these metrics aren't very impressive in the real world, they were a monumental achievement for me. In the beginning I planned on developing it into a fully fledged game, but that never happened.
+I called it {url Mundus;https://gitlab.com/Syndamia/Mundus} and it took me around 3 months to complete and consisted of more than 2000 lines of code. Although these metrics aren't very impressive in the real world, they were a monumental achievement for me. In the beginning I planned on developing it into a fully fledged game, but that never happened.
Nevertheless, this journey was very important to me, hence writing this multi-page article.
-[=Link to the source code=]: [url https://gitlab.com/Syndamia/Mundus GitLab]
+{b Link to the source code}: {url GitLab;https://gitlab.com/Syndamia/Mundus}
## Screenshots
@@ -52,4 +51,4 @@ Nevertheless, this journey was very important to me, hence writing this multi-pa
<img src="./img/inventory-menu.png" style="height: 100%; flex: 1;">
</div>
-[*Screenshots are made on Linux Mint Cinnamon with the Mint-Y theme*]
+{i Screenshots are made on Linux Mint Cinnamon with the Mint-Y theme}
diff --git a/src/blog/mundus-first-shot-at-gamedev/timeline.du b/src/blog/mundus-first-shot-at-gamedev/timeline.du
index 504fe9d..2d4466e 100644
--- a/src/blog/mundus-first-shot-at-gamedev/timeline.du
+++ b/src/blog/mundus-first-shot-at-gamedev/timeline.du
@@ -1,65 +1,63 @@
-# Timeline - Mundus: My first shot at game development
+'def title Timeline - Mundus: My first shot at game development
+'def desc Development timeline of Mundus
-'define expected-reading 6 min
-'define created 21 July 2020
-'define edited 25 November 2020
-[$pagenav]
+# {title}
-'define prev_link ./ Introduction
-'define next_link ./user-interface.html User Interface
-[$pagination_second]
+{pagenav 6 min;21 July 2020;25 November 2020}
-[$due_for_rework]
+{pagination ;Introduction;./;User Interface;./user-interface.html}
-\n
+{due_for_rework}
+
+<br/>
As mentioned, I had big plans for Mundus, so I wanted to make sure it would be well planned. But at the same time, the project took too much energy and I often had holes of no development time. This is an overview of the development "cycle" I went through.
-.quote [*[=08.02.2020=]*]&emsp;Day 0, Hour 0
+.quote {i {b 08.02.2020}}&emsp;Day 0, Hour 0
At this point of time, I was still studying software development in a national program. On this exact day, we had the first lecture of a new module, where it was announced we would have to make a project for the exam. Up until this point of time, our exams constituted of predefined programming exercises for which we would be given a couple of hours to complete and would be checked by an online platform.
I immediately began brainstorming and by the end of the day, I had decided upon the project I would be developing.
-.quote [*[=12.02.2020=]*]&emsp;Day 4
+.quote {i {b 12.02.2020}}&emsp;Day 4
Before Mundus I had experimented with making games, but mostly in the command line. This time was going to be different. Up until this day, I was only researching and trying out different technologies to make my game with.
-Initially I spent a lot of time with Unity, but the original time constraints and my lack of knowledge with the game engine discouraged me from continuing with it. Subsequently, I got discouraged from using any game engine and settled for [`GtkSharp 2.0`]. Now, this is widget toolkit, not even close to a game engine, but hey, it was much better than the command line, it was simple and shipped with the IDE I was using at the time.
+Initially I spent a lot of time with Unity, but the original time constraints and my lack of knowledge with the game engine discouraged me from continuing with it. Subsequently, I got discouraged from using any game engine and settled for {` GtkSharp 2.0}. Now, this is widget toolkit, not even close to a game engine, but hey, it was much better than the command line, it was simple and shipped with the IDE I was using at the time.
This decision proved to have been a mistake down the road, but the clock was ticking and I had no more time to waste. Besides, I also believed that in the end, moving it to something like Unity wouldn't pose too much trouble.
Finally, it was time to plan the actual game.
-.quote [*[=27.02.2020=]*]&emsp;Day 19
+.quote {i {b 27.02.2020}}&emsp;Day 19
So far I have only done preparation but on this day, I started actual programming. The UI and most of the mechanics were completely sketched.
-Around a week later I also drew the first proper textures for the game world: a [url https://gitlab.com/Syndamia/IT-kariera/-/blob/a100f71372496ba89e26fedc520edcefd2442848/Year%202/Software%20development/Mundus/Mundus/Icons/Land/Ground/grass.png tile of grass] <img src="./img/grass-tile.png" class="pixelated-render"> and a [url https://gitlab.com/Syndamia/IT-kariera/-/blob/a100f71372496ba89e26fedc520edcefd2442848/Year%202/Software%20development/Mundus/Mundus/Icons/Land/Ground/boulder.png tile of grass with a boulder on top] <img src="./img/boulder-tile.png" class="pixelated-render">. These replaced the [url https://gitlab.com/Syndamia/IT-kariera/-/blob/7b2c8cbc1d6adb874ca6a41f2871ea1950866d70/Year%202/Software%20development/Project/Mundus/Mundus/Views/Icons/Land/Ground/grass.jpg grass] <img src="./img/placeholder-grass-tile.jpg" class="pixelated-render"> and [url https://gitlab.com/Syndamia/IT-kariera/-/blob/7b2c8cbc1d6adb874ca6a41f2871ea1950866d70/Year%202/Software%20development/Project/Mundus/Mundus/Views/Icons/Land/Ground/rock.jpg rock] <img src="./img/placeholder-rock-tile.jpg" class="pixelated-render"> placeholder textures I made on the 29th.
+Around a week later I also drew the first proper textures for the game world: a {url tile of grass;https://gitlab.com/Syndamia/IT-kariera/-/blob/a100f71372496ba89e26fedc520edcefd2442848/Year%202/Software%20development/Mundus/Mundus/Icons/Land/Ground/grass.png} <img src="./img/grass-tile.png" class="pixelated-render"> and a {url tile of grass with a boulder on top;https://gitlab.com/Syndamia/IT-kariera/-/blob/a100f71372496ba89e26fedc520edcefd2442848/Year%202/Software%20development/Mundus/Mundus/Icons/Land/Ground/boulder.png} <img src="./img/boulder-tile.png" class="pixelated-render">. These replaced the {url grass;https://gitlab.com/Syndamia/IT-kariera/-/blob/7b2c8cbc1d6adb874ca6a41f2871ea1950866d70/Year%202/Software%20development/Project/Mundus/Mundus/Views/Icons/Land/Ground/grass.jpg} <img src="./img/placeholder-grass-tile.jpg" class="pixelated-render"> and {url rock;https://gitlab.com/Syndamia/IT-kariera/-/blob/7b2c8cbc1d6adb874ca6a41f2871ea1950866d70/Year%202/Software%20development/Project/Mundus/Mundus/Views/Icons/Land/Ground/rock.jpg} <img src="./img/placeholder-rock-tile.jpg" class="pixelated-render"> placeholder textures I made on the 29th.
Concerning the temporary textures, I just drew them in half an hour in GIMP, so I could test out some of the code.
The proper textures, I believe, turned out fairly well, given that I've never been good at drawing and this is my very first time trying to draw pixel art. There is no magic behind the process, after scouring the internet for pixel art that looked kinda close to what I imagined, I tried to utilize and mix whatever I found fitting and then just messed around for hours. As you can imagine, this wasn't a very efficient process, and it took me around 1-2 days for both textures.
-.quote [*[=28.03.2020=]*]&emsp;Day 49
+.quote {i {b 28.03.2020}}&emsp;Day 49
Slowly and steadily I had been making fine progress, but a lot of issues started to surface. As it turns out, I hadn't thought everything completely through, so I mostly went back to the drawing board.
-But at the very least, I had some important systems in place, like breaking and placing stuff, proper movement through the map and using items. Also, I had drawn my favorite texture from the whole projects: [url https://gitlab.com/Syndamia/Mundus/-/blob/c47a34847e52ef76361394dba2c4f524a56d1b92/Mundus/Icons/Land/Items/tree.png the tree] <img src="./img/tree-tile.png" class="pixelated-render">.
+But at the very least, I had some important systems in place, like breaking and placing stuff, proper movement through the map and using items. Also, I had drawn my favorite texture from the whole projects: {url the tree;https://gitlab.com/Syndamia/Mundus/-/blob/c47a34847e52ef76361394dba2c4f524a56d1b92/Mundus/Icons/Land/Items/tree.png} <img src="./img/tree-tile.png" class="pixelated-render">.
-.quote [*[=06.04.2020=]*]&emsp;Day 58
+.quote {i {b 06.04.2020}}&emsp;Day 58
Things started to take a turn for the better, I had planned everything I needed to plan and spring break had began. A solid week of no high-school made me more productive than ever. Some days I coded for 8 or even 10 hours straight, from morning to evening. Tools, multiple layers and climbing between them, new items and many bug improvements.
And then, they extended the break for one more week, the productivity boost could've continued even further, but, alas, I was burned out. The productivity boost, as good as it was, it tired me out very fast. There were still a couple of days with progress, but this time I actually took a break.
-\n
+<br/>
However, remember how they extended the spring break by a week? Well, this was caused by the emergence of the COVID-19 pandemic in Europe and Bulgaria. Subsequently, after the break, we didn't go back to school. Due to the emergent situation, development on Mundus became increasingly sporadic and progress slowed down drastically. At least the exam got pushed back by a month/month and a half.
-\n
+<br/>
-.quote [*[=23.05.2020=]*]&emsp;Day 105
+.quote {i {b 23.05.2020}}&emsp;Day 105
Finally, after so much time, and relative amount of hiccups, Mundus was finished. Or at least, finished enough so I could present it on the exam. And this happened just in the nick of time too, the exam date was in 8 days, on the 31st.
diff --git a/src/blog/mundus-first-shot-at-gamedev/user-interface.du b/src/blog/mundus-first-shot-at-gamedev/user-interface.du
index 380c136..9fe7f33 100644
--- a/src/blog/mundus-first-shot-at-gamedev/user-interface.du
+++ b/src/blog/mundus-first-shot-at-gamedev/user-interface.du
@@ -1,61 +1,58 @@
-# User Interface - Mundus: My first shot at game development
+'def title User Interface - Mundus: My first shot at game development
+'def desc Showing and explaining the user interface
-'define expected-reading 4 min
-'define created 21 July 2020
-'define edited 25 November 2020
-[$pagenav]
+# {title}
-'define start_link ./
-'define prev_link ./timeline.html Timeline
-'define next_link ./basic-concepts.html Basic Concepts
-[$pagination_middle]
+{pagenav 4 min;21 July 2020;25 November 2020}
-[$due_for_rework]
+{pagination ./;Timeline;./timeline.html;Basic Concepts;./basic-concepts.html}
+
+{due_for_rework}
\n
.contents
.numbered
-1. [url #main-screen Main screen]
-2. [url #create-new-game Create new game]
-3. [url #game-window Game Window]
-4. [url #map-menu Map menu]
-5. [url #inventory-menu Inventory menu]
-6. [url #crafting-menu Crafting menu]
+1. {uhref Main screen}
+2. {uhref Create new game}
+3. {uhref Game Window}
+4. {uhref Map menu}
+5. {uhref Inventory menu}
+6. {uhref Crafting menu}
The user interface shows how unfinished the whole thing is, you can find many unimplemented options and features. Even then, there is a lot you can do.
-A lot of the topics covered are explained in more detail in [url ./basic-concepts.html Basic Concepts].
+A lot of the topics covered are explained in more detail in {url Basic Concepts;./basic-concepts.html}.
-[=Note:=] all screenshots are made in Linux Mint Cinnamon with Mint-Y theme.
+{b Note:} all screenshots are made in Linux Mint Cinnamon with Mint-Y theme.
## Main screen
-[image ./img/main-screen.png]
+{img ./img/main-screen.png}
We start off with the main screen.
-Only the [`Create a new game`] button is implemented, although the [`Settings`] one does open a blank window.
+Only the {` Create a new game} button is implemented, although the {` Settings} one does open a blank window.
## Create new game
-[image ./img/create-new-game.png]
+{img ./img/create-new-game.png}
Creating a game gives you a couple of options:
-[`Game Mode`] - Survival is the only implemented option, where you start with almost no items and have to gather food and materials. Creative was supposed to be the opposite, giving you access to all items and making you invincible.
+{` Game Mode} - Survival is the only implemented option, where you start with almost no items and have to gather food and materials. Creative was supposed to be the opposite, giving you access to all items and making you invincible.
-[`Difficulty`] - Higher the difficulty, the more your energy gets depleted and the less trees, boulders and mobs there are.
+{` Difficulty} - Higher the difficulty, the more your energy gets depleted and the less trees, boulders and mobs there are.
-[`Screen & Inventory size`] - The screen is where you navigate the in game world. The way the user interface works, both are linked.
+{` Screen & Inventory size} - The screen is where you navigate the in game world. The way the user interface works, both are linked.
-[`Map size`] - Map size (in survival mode) is determined by the Screen & Inventory size, the higher the size, the smaller the map.
+{` Map size} - Map size (in survival mode) is determined by the Screen & Inventory size, the higher the size, the smaller the map.
-[=Note:=] all game window screenshots are made with the [`Small Game Window`].
+{b Note:} all game window screenshots are made with the {` Small Game Window}.
## Game Window
-[image ./img/small-game-window.png]
+{img ./img/small-game-window.png}
After the world is generated, the game window opens.
@@ -67,26 +64,26 @@ Then you have your health. It represents how much life you have. If it drops to
Underneath that, there is your hotbar. It is a part of your inventory.
-After that, you have the [`Event log`] button and some of the most recent events. Clicking the button opens a window from which you can checkout everything that has happened. On the sides, you can find the [`Map`] and [`Inv`] toggle buttons and the [`Pause`] and [`Music`] menu buttons. The [`Music`] menu can only play and stop WAV files.
+After that, you have the {` Event log} button and some of the most recent events. Clicking the button opens a window from which you can checkout everything that has happened. On the sides, you can find the {` Map} and {` Inv} toggle buttons and the {` Pause} and {` Music} menu buttons. The {` Music} menu can only play and stop WAV files.
## Map menu
-[image ./img/map-menu.png]
+{img ./img/map-menu.png}
The Map menu is an extension (to the left) of the normal game window. It cannot be opened at the same time as the inventory menu.
-At the top, you can see the ground layer tiles. Below it you can find the name of the superlayer you're currently in and your coordinates. At the bottom there are the structure layer tiles and [`There is a hole above player`] field, where you can check whether you are able to ascent a superlayer.
+At the top, you can see the ground layer tiles. Below it you can find the name of the superlayer you're currently in and your coordinates. At the bottom there are the structure layer tiles and {` There is a hole above player} field, where you can check whether you are able to ascent a superlayer.
## Inventory menu
-[image ./img/inventory-menu.png]
+{img ./img/inventory-menu.png}
The Inventory menu is an extension (to the right) of the normal game window. From here you can store your items, organize them, craft and see information about a given item.
## Crafting window
-[image ./img/crafting-window.png]
+{img ./img/crafting-window.png}
Every time you open the crafting menu, it automatically finds all items that you can craft using the items in your "Items inventory".
-At the top it shows you what items and how much of them you need to craft the currently selected item. Below that it shows the item that you can craft and the [`Prev`] and [`Next`] buttons for navigating available items to craft. Finally, there is the [`Craft`] button. Clicking it removes the required items and adds the crafted item to your inventory.
+At the top it shows you what items and how much of them you need to craft the currently selected item. Below that it shows the item that you can craft and the {` Prev} and {` Next} buttons for navigating available items to craft. Finally, there is the {` Craft} button. Clicking it removes the required items and adds the crafted item to your inventory.
diff --git a/src/blog/plan9-in-linux-mouse-menus/index.du b/src/blog/plan9-in-linux-mouse-menus/index.du
index e558f6b..79f391e 100644
--- a/src/blog/plan9-in-linux-mouse-menus/index.du
+++ b/src/blog/plan9-in-linux-mouse-menus/index.du
@@ -1,38 +1,31 @@
-# Plan 9 in Linux: Mouse menus
+'def title Plan 9 in Linux: Mouse menus
+'def desc Writing a scripts which implements the Plan 9 mouse menus functionality
-'define expected-reading 17 min
-'define created 10 January 2023
-'define edited 28 March 2023
-[$pagenav]
+# {title}
+
+{pagenav 17 min;10 January 2023;28 March 2023}
.contents
.numbered
-1. [url #usefulness-in-linux Usefulness in Linux]
-2. [url #going-about-it Going about it]
+1. {uhref Usefulness in Linux}
+2. {uhref Going about it}
.bulleted
- - [url #1 \#1]
- - [url #2 \#2]
- - [url #3 \#3]
- - [url #4 \#4]
+ - {uhref #1}
+ - {uhref #2}
+ - {uhref #3}
+ - {uhref #4}
.bulleted
- - [url #open-files Open files]
- - [url #send Send]
- - [url #window-management Window management]
-
-'footnote plan9-vs-rio When I say "Plan 9" in the context of graphical stuff, I usually refer to the default window system [url https://9p.io/magic/man2html/1/rio rio]. Similarly to most UNIX-like OSs, it can be changed, but there doesn't seem to be any others out there[*[^citation ^needed]*].
+ - {uhref Open files}
+ - {uhref Send}
+ - {uhref Window management}
-Let's begin with an introduction to Plan 9 (from Bell Labs): it is an old UNIX-like operating system from the 90s, where[$plan9-vs-rio] everything is pretty much either text, image or some sort of rectangular box.
+Let's begin with an introduction to Plan 9 (from Bell Labs): it is an old UNIX-like operating system from the 90s, where{fn I say "Plan 9" in the context of graphical stuff, I usually refer to the default window system {url rio;https://9p.io/magic/man2html/1/rio}. Similarly to most UNIX-like OSs, it can be changed, but there doesn't seem to be any others out there{i {^ citation needed}}.} everything is pretty much either text, image or some sort of rectangular box.
There are no fancy graphical menus of any kind, no title bars, no file managers and nothing utilizes icons, but the window manager is still stacked.
-'footnote acme acme actually changes how the three mouse buttons work. Paraphrasing the [url https://9p.io/wiki/plan9/Using_acme/index.html official page], button 2 "executes things" and button 3 gets or searches for things.
-
Everything is done with text, actions in a window can be done by "clicking" any text inside that corresponds to an available action.
-For example, in the main text editor "acme", you open a file by just pressing[$acme] on a string "New", which for convenience is always available up top:
+For example, in the main text editor "acme", you open a file by just pressing{fn acme actually changes how the three mouse buttons work. Paraphrasing the {url official page;https://9p.io/wiki/plan9/Using_acme/index.html}, button 2 "executes things" and button 3 gets or searches for things.} on a string "New", which for convenience is always available up top:
-<video width="376" height="194" controls>
- <source src="./vid/acme-demo.mp4" type="video/mp4">
-Your browser doesn't support the video tag
-</video>
+{vid ./vid/acme-demo.mp4}
How you manage windows and differentiate between selecting some text and "executing" it is done entirely via a three-button mouse.
Each button corresponds to some sort of action, and different application can configure how every button works, which is why I'll only work with the "default" options in the desktop and terminal windows.
@@ -42,30 +35,23 @@ The left mouse button (button 1), works as expected: you use it to select text.
Pressing and holding down the right mouse button (button 3), shows all possible window options:
-[image ./img/plan9-mouse3-menu.png]
+{img ./img/plan9-mouse3-menu.png}
For example, if you release it while hovering "New", you cursor will change, and after holding it down again, dragging out will result in a grey rectangle representing the dimensions (and position) of a new terminal window (releasing the button creates that new window).
-<video width="376" height="194" controls>
- <source src="./vid/new-window.mp4" type="video/mp4">
-Your browser doesn't support the video tag
-</video>
+{vid ./vid/new-window.mp4}
-"Opening" an application is always done via a command in the terminal, where the program will [url https://9p.io/wiki/plan9/Using_rio/index.html "take over the window"].
+"Opening" an application is always done via a command in the terminal, where the program will {url "take over the window";https://9p.io/wiki/plan9/Using_rio/index.html}.
Finally, the middle mouse button (button 2), shows text-control options, which can be executed on selected text:
-[image ./img/plan9-mouse2-menu.png]
-
-'footnote snarf It's hard to deduce why exactly it was named like this, but the most probable explanation comes from [url https://unix.stackexchange.com/questions/308943/why-does-plan-9-use-snarf-instead-of-copy/309350 unix.stackexchange]: copying might've been seen as a two step action, obtain the contents you want to copy and paste them somewhere. So to copy something you need a duplicate of itself to be created, and either putting it in the "clipboard" isn't considered duplicating, or an optimization makes "the clipboard" store some sort of reference to what you snarfed, but not the exact thing itself. \n On an unrelated note, this might have played a part in the reasoning behind vim using the word "yank" for copy.
-
-'footnote plumber-in-apps Technically, a plumber just passes messages between applications, so you can configure it to not open a URL but do something else with it in a certain application. However, the aforementioned way is how it works most of the time.
+{img ./img/plan9-mouse2-menu.png}
-You'll recognise [`cut`], [`paste`] and [`snarf`] [$snarf], the latter being just another word for copy.
+You'll recognise {` cut}, {` paste} and {` snarf} {fn It's hard to deduce why exactly it was named like this, but the most probable explanation comes from {url unix.stackexchange;https://unix.stackexchange.com/questions/308943/why-does-plan-9-use-snarf-instead-of-copy/309350}: copying might've been seen as a two step action, obtain the contents you want to copy and paste them somewhere. So to copy something you need a duplicate of itself to be created, and either putting it in the "clipboard" isn't considered duplicating, or an optimization makes "the clipboard" store some sort of reference to what you snarfed, but not the exact thing itself. \n On an unrelated note, this might have played a part in the reasoning behind vim using the word "yank" for copy.}, the latter being just another word for copy.
Since every modern window manager supports those in some form, I'll concentrate on the others.\n
-[`plumb`] is the most interesting: it sends the selection to a "plumber" application, which practically[$plumber-in-apps] tries to open or execute it.
+{` plumb} is the most interesting: it sends the selection to a "plumber" application, which practically{fn Technically, a plumber just passes messages between applications, so you can configure it to not open a URL but do something else with it in a certain application. However, the aforementioned way is how it works most of the time.} tries to open or execute it.
For example, a selected URL will open in the browser, but a selected image file will open in an image viewer.\n
-[`send`] enters the selected text as a command in the current shell.
+{` send} enters the selected text as a command in the current shell.
### Usefulness in Linux
@@ -91,11 +77,11 @@ Most importantly, this works in any application, any time, any where, as long as
### Going about it
-This could all be done with a C program, but writing the code would take way too much time (if you do it like that, [url /about tell me about it]), so everything should be contained in a couple of shell scripts.
+This could all be done with a C program, but writing the code would take way too much time (if you do it like that, {url tell me about it;/about}), so everything should be contained in a couple of shell scripts.
Another "constraint" is that I use openbox, an X11 window manager, so my solution will be oriented around tools that work with it.
The result should be simple enough that adapting it to your window manager shouldn't take too much effort.
-Looking around, you would first find a video by Luke Smith, where he creates a small plumber in bash ([url https://www.youtube.com/watch?v=RlMxbQmMz_4 YouTube link], [url https://odysee.com/@Luke:7/plumbing-in-linux-la-plan-9-from-bell:e Odysee link]) and an [url https://tatsumoto-ren.github.io/blog/plumbing-for-language-learners.html expansion of it] by Ren Tatsumoto (surprisingly enough from around 3 months before I started).
+Looking around, you would first find a video by Luke Smith, where he creates a small plumber in bash ({url YouTube link;https://www.youtube.com/watch?v=RlMxbQmMz_4}, {url Odysee link;https://odysee.com/@Luke:7/plumbing-in-linux-la-plan-9-from-bell:e}) and an {url expansion of it;https://tatsumoto-ren.github.io/blog/plumbing-for-language-learners.html} by Ren Tatsumoto (surprisingly enough from around 3 months before I started).
These posts served as a good base and inspiration.
Following their steps, everything will be done via one shell script that does something on the text selection, effectively allowing the menus, plumber and all other possible actions to be managed by that script.
@@ -112,27 +98,28 @@ The overall life cycle is split into four parts:
Since we're emulating Plan 9, I wanted the script to be ran with the mouse, with potentially different parameters depending on button.
Ideally, if you quickly press and release a button (button 2 or 3), the click should be sent to the application below the cursor, but if you hold it, the script should be ran.
-A tool that allows that (mentioned in Ren Tatsumoto's [url https://tatsumoto-ren.github.io/blog/plumbing-for-language-learners.html blog post]) is [url https://github.com/baskerville/sxhkd sxhkd].
-Sparing you the details, unfortunately sxhkd cannot pass the mouse press to the application below, if you want something to also happen on key-down ([url https://github.com/baskerville/sxhkd/issues/198 Issue 198], and the workaround in didn't work).
+A tool that allows that (mentioned in Ren Tatsumoto's {url blog post;https://tatsumoto-ren.github.io/blog/plumbing-for-language-learners.html}) is {url sxhkd;https://github.com/baskerville/sxhkd}.
+Sparing you the details, unfortunately sxhkd cannot pass the mouse press to the application below, if you want something to also happen on key-down ({url Issue 198;https://github.com/baskerville/sxhkd/issues/198}, and the workaround in didn't work).
This means that the original idea isn't really feasible, but I couldn't really find any other good tool that does what I wanted.
Plan B: execute the plumbing script on KeyboardKey + Button, but what key should I choose, especially when we're binding the right click?
Ctrl + Button3 is used for opening links, Alt + Button3 is reserved for resizing the current window and binding with the Super (Windows) key causes issues with opening of my application menu.
-After a lot of research, I found out there is actually a fourth modifier key, called [`Hyper`], which X11 still supports.
-It's inception come from 1978 with the [url https://en.wikipedia.org/wiki/Space-cadet_keyboard Space-cadet keyboard], but thanks to the popularity of the [url https://en.wikipedia.org/wiki/Model_M_keyboard Model M], modern keyboards don't include it.
+After a lot of research, I found out there is actually a fourth modifier key, called {` Hyper}, which X11 still supports.
+It's inception come from 1978 with the {url Space-cadet keyboard;https://en.wikipedia.org/wiki/Space-cadet_keyboard}, but thanks to the popularity of the {url Model M;https://en.wikipedia.org/wiki/Model_M_keyboard}, modern keyboards don't include it.
-All that was left was to assign [`Hyper`] to some key that I don't use, and what better than Caps Lock!
-There are [url https://en.jveweb.net/archives/2010/11/making-better-use-of-the-caps-lock-key-in-linux.html many ways to do it], but I prefer using [url https://gitlab.freedesktop.org/xorg/app/setxkbmap setxkbmap]:
+All that was left was to assign {` Hyper} to some key that I don't use, and what better than Caps Lock!
+There are {url many ways to do it;https://en.jveweb.net/archives/2010/11/making-better-use-of-the-caps-lock-key-in-linux.html}, but I prefer using {url setxkbmap;https://gitlab.freedesktop.org/xorg/app/setxkbmap}:
```
setxkbmap -option "caps:hyper"
-This line is needs to be ran at start of openbox, so it's placed inside [`~/.config/openbox/autostart`].
+This line is needs to be ran at start of openbox, so it's placed inside {` ~/.config/openbox/autostart}.
-Now, finally, our sxhkd config looks something like this (I named the script [`plumb.sh`]):
+Now, finally, our sxhkd config looks something like this (I named the script {` plumb.sh}):
-:code
+```
+'emplace
# Hyper_L + Middle mouse button
mod4 + button2
$HOME/.a/plumb.sh 1
@@ -140,9 +127,9 @@ mod4 + button2
# Hyper_L + Right mouse button
mod4 + button3
$HOME/.a/plumb.sh
+'endemplace
-
-For details about these options, refer to the [url https://github.com/baskerville/sxhkd/blob/master/doc/sxhkd.1.asciidoc manpage].
+For details about these options, refer to the {url manpage;https://github.com/baskerville/sxhkd/blob/master/doc/sxhkd.1.asciidoc}.
What you might notice is that on middle mouse button, "1" is passed to the script.
Since the window options aren't very useful, I've configured the script to execute a "default" action on Hyper\_L+Button2, but show me a list of all possible on Hyper\_L+Button3.
@@ -151,9 +138,9 @@ Feel free to change this behaviour.
#### #2
Getting the current selection turns out to be easy, X11's selections (clipboard) is split into a primary, secondary and a clipboard, where the primary is the current selection you've done with your mouse, the secondary isn't used, and the clipboard is what you know and love.
-[url https://www.uninformativ.de/ uninformativ.de] has a great blog post about [url https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html X11's "clipboard"], I recommend it, even though it dives more into C than one would like.
+{url uninformativ.de;https://www.uninformativ.de/} has a great blog post about {url X11's "clipboard";https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html}, I recommend it, even though it dives more into C than one would like.
-As for getting it inside our script, [url https://github.com/astrand/xclip xclip] is a perfect choice.
+As for getting it inside our script, {url xclip;https://github.com/astrand/xclip} is a perfect choice.
In the very beginning, we'll just store the selection in a variable and work from there:
```bash
@@ -162,10 +149,10 @@ selection="$(xclip -o)"
#### #3
With that out of the way, all we now need is an actual menu to appear.
-Luke Smith and Ren Tatsumoto both used [url https://tools.suckless.org/dmenu/ dmenu], which is keyboard driven.
-As for a mouse-oriented standalone menu, that could be easily configured, all I could find was my current application menu: [url https://jgmenu.github.io/ jgmenu].
+Luke Smith and Ren Tatsumoto both used {url dmenu;https://tools.suckless.org/dmenu/}, which is keyboard driven.
+As for a mouse-oriented standalone menu, that could be easily configured, all I could find was my current application menu: {url jgmenu;https://jgmenu.github.io/}.
-Generally it is meant to serve as an application menu, but with [`--simple`] you can directly echo and pipe to it all menu option and what they do.
+Generally it is meant to serve as an application menu, but with {` --simple} you can directly echo and pipe to it all menu option and what they do.
Menu options are formatted as comma-separated (CSV) text, where each option is on a new line, the first item being the name, and the second, the executed command upon press:
```
@@ -176,65 +163,71 @@ Move,echo 3
In this case I'm echo-ing a number, rather than doing an action, for readability and formatting sake.
The number is parsed by a switch statement, so all actions are in a single place and can be more easily formatted than if they were inlined in the string.
-Via [`--at-pointer`] the menu can spawn right under the pointer.
+Via {` --at-pointer} the menu can spawn right under the pointer.
Unfortunately it always spawns in such a way that the pointer is at the top-left corner, I couldn't find a way to make it appear in a way that the first option is below the pointer.
Finally, since I use it as an application menu too, I specify a config file which makes it look more like Plan 9's menu (though I've personally omitted the color scheme, since it doesn't fit my normal theme):
```
-'include ./jgmenurc
+'snippet 1 $ ./jgmenurc
-More info on these options can be found in the [url https://jgmenu.github.io/jgmenu.1.html manpage].
+More info on these options can be found in the {url manpage;https://jgmenu.github.io/jgmenu.1.html}.
Putting it all together, it looks something like this:
-```bash
+````bash
'snippet 54 54 ./plumb.sh
'snippet 58 59 ./plumb.sh
1) ...
;;
2) ...
;;
- ...
-\
+ \...
+
*) ...
;;
-'snippet 81 $ ./plumb.sh
+'snippet 81 $ ./plumb.sh
+
+
An important aspect of our menu options is that they can change depending on context.
For example, if we have a URL we might want the options "Open it in browser" and "Download", which we wouldn't want in case of a .docx file.
Or we might want it "ship" it with a lot of possible menu options and let the user decide which ones they need.
This is very simple to do, and can be done in many ways.
-My preferred way is to have a variable [`menu`] to which different options are appended depending on a regular expression or "flag" (variable).
+My preferred way is to have a variable {` menu} to which different options are appended depending on a regular expression or "flag" (variable).
To work with regular expressions more easily, I've made a function which returns a status code depending on matching.
All in all, it would look something like this:
-```bash
+````bash
'snippet 26 26 ./plumb.sh
'snippet 28 38 ./plumb.sh
'snippet 45 46 ./plumb.sh
-\
+
'snippet 54 54 ./plumb.sh
'snippet 58 59 ./plumb.sh
- ...
-'snippet 81 $ ./plumb.sh
+ \...
+'snippet 81 $ ./plumb.sh
+
+
#### #4
-Finally, we need to execute a selected option, aka put commands in each case of [`\$action`].
+Finally, we need to execute a selected option, aka put commands in each case of {` \$action}.
##### Open files
-Opening a file is very simple, [`xdg-open`] handles opening files by name, with the default program for that file extension.
+Opening a file is very simple, {` xdg-open} handles opening files by name, with the default program for that file extension.
However, the script is ran completely independently from the current program, so when we're given only a part of the file path, we need to figure out the rest.
-This problem was solved somewhat by Luke Smith, he figured out a way to find (and [`cd`] into) the current directory of the active window ([`pid1`] should be [`pid`], but you'll see later why I did that change):
+This problem was solved somewhat by Luke Smith, he figured out a way to find (and {` cd} into) the current directory of the active window ({` pid1} should be {` pid}, but you'll see later why I did that change):
```bash
+'emplace
pid=$(xprop -id "$(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $NF}')" | grep -m 1 PID | cut -d " " -f 3)
-pid1=$(pstree -lpA "$pid" | tail -n 1 | awk -F'---' '{print $NF}' | sed -re 's/[^0-9]//g')
+pid1=$(pstree -lpA "$pid" | tail -n 1 | awk -F'---' '{print $NF}' | sed -re 's/{^ 0-9]//g')
cd "$(readlink /proc/"$pid1"/cwd)"
+'endemplace
Still, one important situation where this doesn't work is tabs, but those are handled differently from application to application.
I figured out tabs only for terminal emulators, since that's where text actions can be the most useful.
@@ -244,24 +237,20 @@ We only get the active window, but there is no way to get the active/currently "
Additionally, pretty much all terminal emulators have different shell, not terminal, processes for the different tabs.
Terminal plugins/extensions and special application were considered, but they would take too much effort and/or couldn't work.
-'footnote shell-cwd You could make a proper mechanism, which waits for the file to get updated ([url https://github.com/inotify-tools/inotify-tools inotify-wait]), or for there to be a lockfile, but the overall way it works is the same. I couldn't think of anything better, mostly because the plumber script is a completely separate process from the shell you're in. Maybe there is a way for them to communicate between each other, a bit like microservices?
-
In the end, I settled on a hack: the shell would do the heavy lifting.
-My right-click menu combination would be passed to the terminal (and therefore to the shell), and the shell will simultaneously store it's working directory in a file inside [`/tmp`], which could then be parse by the script.
-This isn't ideal, since if the shell is being slow, the script might not wait long enough for the file to get updated, but I couldn't think of anything much better[$shell-cwd] and it does the job.
-
-'footnote escape-sequences The terminal emulator passes keyboard presses to the shell via [url https://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape sequences], which don't support [`Hyper`] bindings. I settled for the next best thing, which is create a different key combination that isn't in use, and make our script "press" that combination upon running.
+My right-click menu combination would be passed to the terminal (and therefore to the shell), and the shell will simultaneously store it's working directory in a file inside {` /tmp}, which could then be parse by the script.
+This isn't ideal, since if the shell is being slow, the script might not wait long enough for the file to get updated, but I couldn't think of anything much better{fn You could make a proper mechanism, which waits for the file to get updated ({url inotify-wait;https://github.com/inotify-tools/inotify-tools}), or for there to be a lockfile, but the overall way it works is the same. I couldn't think of anything better, mostly because the plumber script is a completely separate process from the shell you're in. Maybe there is a way for them to communicate between each other, a bit like microservices?} and it does the job.
I use zsh, so I implemented it by creating a zsh widget: certain functionality that can be ran by the shell itself and (usually) doesn't need to be executed like a normal program.
Examples include key binds, completion, navigation through history, undo and redo.
-User-defined widgets are just zsh functions, so we create a function that stores the current directory, add it as a widget and bind it to our keyboard combination[$escape-sequences]:
+User-defined widgets are just zsh functions, so we create a function that stores the current directory, add it as a widget and bind it to our keyboard combination{fn The terminal emulator passes keyboard presses to the shell via {url ANSI escape sequences;https://en.wikipedia.org/wiki/ANSI_escape_code}, which don't support {` Hyper} bindings. I settled for the next best thing, which is create a different key combination that isn't in use, and make our script "press" that combination upon running.}:
```bash
plumb-store-cwd () {
pwd > /tmp/plumb-cwd
}
zle -N plumb-store-cwd
-bindkey "[^[5;7~" plumb-store-cwd # Ctrl+Alt+Page_Up
+bindkey "{^ [5;7~" plumb-store-cwd # Ctrl+Alt+Page_Up
Finally, in our script, we want to read that file, only if we're inside a terminal:
@@ -273,12 +262,12 @@ if [ $wname == "TERMINAL" ]; then # Replace with your terminal emulator name
cd "$(cat /tmp/plumb-cwd)"
fi
-For the uninitiated, [url https://github.com/jordansissel/xdotool xdotool] is a general X11 tool, which allows (amongst other things) to "execute" key presses via commands.
+For the uninitiated, {url xdotool;https://github.com/jordansissel/xdotool} is a general X11 tool, which allows (amongst other things) to "execute" key presses via commands.
##### Send
Sending the command to the current shell is by far the simplest action.
-[`xdotool`] supports "typing out" text, so I'll give it the selection and let it do it's thing:
+{` xdotool} supports "typing out" text, so I'll give it the selection and let it do it's thing:
```bash
xdotool type --delay 0 "$selection"
@@ -297,12 +286,14 @@ xdotool mousedown 3
xdotool keyup Alt
After this is executed, moving the mouse will cause the screen to be resized, the same way if I did the original combination.
-Pressing and releasing the mouse button will stop resizing (that's why [`keyup Alt`] is done, because otherwise you would need to also press Alt).
+Pressing and releasing the mouse button will stop resizing (that's why {` keyup Alt} is done, because otherwise you would need to also press Alt).
Though it work, it's kind of clunky and the normal Alt+RightClick is arguably simpler and easier to work with.
-\n
+<br/>
With this our script if finished.
-You can find the whole thing (including some personal modifications) in my [url https://gitlab.com/Syndamia/dotfiles/-/blob/main/.a/plumb.sh dotfiles].
+You can find the whole thing (including some personal modifications) in my {url dotfiles;https://gitlab.com/Syndamia/dotfiles/-/blob/main/.a/plumb.sh}.
I'll try to use it as much as I can and I might create a blog post or an appendix on how I feel about it.
+
+{footnotes}
diff --git a/src/blog/remove-weather-widget/index.du b/src/blog/remove-weather-widget/index.du
index 5e2aa28..efa5096 100644
--- a/src/blog/remove-weather-widget/index.du
+++ b/src/blog/remove-weather-widget/index.du
@@ -1,19 +1,19 @@
-# How to remove Windows Weather Widget
+'def title How to remove Windows Weather Widget
+'def desc From June 2021 Microsoft introduced the Weather Widget on Windows 10. It takes up space on the taskbar and is a huge mess.
-'define expected-reading 1 min
-'define created 26 October 2021
-'define edited 26 October 2021
-[$pagenav]
+# {title}
-From June 2021 Microsoft introduced the [`Weather Widget`] on Windows 10. Given that it takes up space on the taskbar [url https://www.howtogeek.com/734461/windows-10s-weather-widget-is-a-mess.-is-windows-11-next/ and is a huge mess], you might want to remove it.
+{pagenav 1 min;26 October 2021;26 October 2021}
+
+From June 2021 Microsoft introduced the {` Weather Widget} on Windows 10. Given that it takes up space on the taskbar {url and is a huge mess;https://www.howtogeek.com/734461/windows-10s-weather-widget-is-a-mess.-is-windows-11-next/}, you might want to remove it.
This is how:
:ordered
1. Right-click on an empty spot in the taskbar
- [image ./img/windows10-taskbar.png]
+ {img ./img/windows10-taskbar.png}
-2. Go up to [*News and interests*], and then click [*Turn off*] in the popped up window
+2. Go up to {i News and interests}, and then click {i Turn off} in the popped up window
- [image ./img/remove-newsweather-windows10.png]
+ {img ./img/remove-newsweather-windows10.png}
diff --git a/src/blog/sane-explanation-of-compilers/index.du b/src/blog/sane-explanation-of-compilers/index.du
index 9c05e81..99b34fd 100644
--- a/src/blog/sane-explanation-of-compilers/index.du
+++ b/src/blog/sane-explanation-of-compilers/index.du
@@ -1,12 +1,12 @@
-# Sane explanation of compilers
+'def title Sane explanation of compilers
+'def desc A series of blog posts, explaining compilers in a simple manner
-'define expected-reading 48 min
-'define created 30 March 2023
-'define edited 24 April 2023
-[$pagenav]
+# {title}
+
+{pagenav 48 min;30 March 2023;24 April 2023}
This is a series on compilers, with the goal of explaining all topics as simply as possible.
More information is available in the first part.
.bulleted
-- [url ./part-1 Part 1]: Introduction and The frontend (aka How do we understand code)
+- {url Part 1;./part-1}: Introduction and The frontend (aka How do we understand code)
diff --git a/src/blog/sane-explanation-of-compilers/part-1/index.du b/src/blog/sane-explanation-of-compilers/part-1/index.du
index e06bad4..125c778 100644
--- a/src/blog/sane-explanation-of-compilers/part-1/index.du
+++ b/src/blog/sane-explanation-of-compilers/part-1/index.du
@@ -1,42 +1,42 @@
-# Sane explanation of compilers: Part 1
+'def title Sane explanation of compilers: Part 1
+'def desc An introduction to regular expressions, grammars, lexers and parsers for use in compilers with some lex and yacc implementations
-'define expected-reading 48 min
-'define created 30 March 2023
-'define edited 24 April 2023
-[$pagenav]
+# {title}
+
+{pagenav 48 min;30 March 2023;24 April 2023}
:contents
:numbered
-1. [url #preface Preface]
-2. [url #i.-how-do-we-understand-code I. How do we understand code?]
+1. {uhref Preface}
+2. {uhref I. How do we understand code?}
:numbered
- 1. [url #math Math]
+ 1. {uhref Math}
.numbered
- 1. [url #regular-expressions Regular expressions]
- 2. [url #grammars Grammars]
+ 1. {uhref Regular expressions}
+ 2. {uhref Grammars}
- 2. [url #lexers-and-parsers Lexers and parsers]
+ 2. {uhref Lexers and parsers}
:numbered
- 1. [url #implementational-difficulties-with-grammars Implementational difficulties with grammars]
- 2. [url #practical-usage Practical usage]
- 3. [url #parsing-algorithms Parsing algorithms]
+ 1. {uhref Implementational difficulties with grammars}
+ 2. {uhref Practical usage}
+ 3. {uhref Parsing algorithms}
.numbered
- 1. [url #ll LL]
- 2. [url #lr LR]
- 3. [url #lrs-family LR's family]
- 4. [url #more-info More info]
+ 1. {uhref LL}
+ 2. {uhref LR}
+ 3. {uhref LR's family}
+ 4. {uhref More info}
- 4. [url #abstract-syntax-tree Abstract syntax tree]
+ 4. {uhref Abstract syntax tree}
- 3. [url #implementing-a-front-end Implementing a front-end]
+ 3. {uhref Implementing a front-end}
.numbered
- 1. [url #lex lex]
- 2. [url #yacc yacc]
- 3. [url #doing-it-properly Doing it properly]
+ 1. {uhref lex}
+ 2. {uhref yacc}
+ 3. {uhref Doing it properly}
-3. [url #appendix Appendinx]
+3. {uhref Appendinx}
@@ -50,11 +50,9 @@ Processors work with numbers, every action (instruction) a processor can do is d
However, writing code only with numbers is tedious, error-prone and simple stuff sometimes take ages to implement.
That is why, over time, programmers have tried to abstract sets of instructions into words and text constructions that are easier to work with.
-'footnote how-did-we-get-here Though it's obvious, I would like to point out that modern compilers are most often written in languages that are themselves compiled. You might ask yourself "where did the first compiler come from?" The answer is simple: it was written with "numbers", with direct instructions to the processor, from the time when computers were simple enough that [*all*] programming was done with CPU instructions.
-
Thanks to abstraction, programmers have been able to create more and more complicated projects with less and less work, that is more portable and compatible with different machines.
The trade-off is that we need to translate our nice programmer code to numbers a CPU would understand.
-This job is delegated to a special type of program, called a compiler[$how-did-we-get-here], which is separated into three main layers/components:
+This job is delegated to a special type of program, called a compiler{fn Though it's obvious, I would like to point out that modern compilers are most often written in languages that are themselves compiled. You might ask yourself "where did the first compiler come from?" The answer is simple: it was written with "numbers", with direct instructions to the processor, from the time when computers were simple enough that {i all} programming was done with CPU instructions.}, which is separated into three main layers/components:
.numbered
1. Front-end: it understands the program, what the code is trying to do
@@ -65,7 +63,7 @@ In this post, we'll be looking only at the first one.
## I. How do we understand code?
-Syntax in current programming languages can be quite sophisticated and ambiguous. For example (taken from [url https://en.wikipedia.org/wiki/Most_vexing_parse wikipedia]) this C++ snippet
+Syntax in current programming languages can be quite sophisticated and ambiguous. For example (taken from {url wikipedia;https://en.wikipedia.org/wiki/Most_vexing_parse}) this C++ snippet
```
void f(double d) {
@@ -75,12 +73,12 @@ void f(double d) {
could be interpreted either as a:
.numbered
-1. declaration of variable [`i`], which is initialized with the value of [`int(d)`] (which just casts [`d`] to an integer), or
-2. function declaration, since superfluous parenthesis around function parameter declarations are allowed (meaning it is treated as [`int i(int d)`])
+1. declaration of variable {` i}, which is initialized with the value of {` int(d)} (which just casts {` d} to an integer), or
+2. function declaration, since superfluous parenthesis around function parameter declarations are allowed (meaning it is treated as {` int i(int d)})
Note that I'm talking about syntax, the valid selection and layouts of characters, and not semantics, the underlying meaning.
Compiled programming languages associate specific templates of code (text) to their "corresponding" machine instructions, there isn't anything special you need to understand in a piece of code.
-In natural languages, you could construct a sentence which follows all grammatical rules, but is absolute nonsense, like [url https://en.wikipedia.org/wiki/Colorless_green_ideas_sleep_furiously "Colorless green ideas sleep furiously"].
+In natural languages, you could construct a sentence which follows all grammatical rules, but is absolute nonsense, like {url "Colorless green ideas sleep furiously";https://en.wikipedia.org/wiki/Colorless_green_ideas_sleep_furiously}.
The problem of semantics is extremely difficult, however in our case we only care about syntax.
And this is where math comes into play.
@@ -90,7 +88,7 @@ And this is where math comes into play.
A word of caution, I'll use a decent amount of fancy names, so I have a way to more easily refer to different concepts.
Don't be scared and skip over them if they're confusing you.
-There is a special field in mathematics that deals with syntactical analysis: [url https://en.wikipedia.org/wiki/Formal_language formal language theory].
+There is a special field in mathematics that deals with syntactical analysis: {url formal language theory;https://en.wikipedia.org/wiki/Formal_language}.
Although even the basics merit a whole university course, I'll still try to roughly explain what's important, for those that haven't studied it.\n
This field works primarily with strings via the help of two (relevant for our purposes) instruments: regular expressions and grammars.
@@ -103,104 +101,110 @@ When a word can be "generated" from the pattern, we say the regex matches the wo
At their very base, such a pattern is created with the following rules:
:unordered
-- [url https://en.wikipedia.org/wiki/Concatenation concatenation] - you can put characters next to each other to form strings, so a normal string like [`accent`] is also a regex.\n
+- {url concatenation;https://en.wikipedia.org/wiki/Concatenation} - you can put characters next to each other to form strings, so a normal string like {` accent} is also a regex.\n
With braces we can group stuff.
- For example, in [`a(cc)ent`] the two "c"s are grouped together.
- This is used to form more sophisticated structures later on, but currently it doesn't alter anything, like the braces in [`(1+2)+3`] and [`1+(2+3)`] don't alter the result sum.
+ For example, in {` a(cc)ent} the two "c"s are grouped together.
+ This is used to form more sophisticated structures later on, but currently it doesn't alter anything, like the braces in {` (1+2)+3} and {` 1+(2+3)} don't alter the result sum.
-- [url https://en.wikipedia.org/wiki/Alternation_%28formal_language_theory%29 alternation] - allow different (alternative) strings in the same spot.\n
+- {url alternation;https://en.wikipedia.org/wiki/Alternation_%28formal_language_theory%29} - allow different (alternative) strings in the same spot.\n
We do so with vertical bars (which signify an "or" relationship), the group can be "replaced" with either value.
- For example [`acce(n | p)t`], matches both "acce[=n=]t" or "acce[=p=]t".\n
+ For example {` acce(n | p)t}, matches both "acce{b n}t" or "acce{b p}t".\n
There is no limit on how many alternatives you can have and what their lengths are:
- ```regex
+ 'def LANG regex
+ ```
acc(ordingly | ent | urate)
matches
.bulleted
- - "acc[=ordingly=]"
- - "acc[=ent=]" and
- - "acc[=urate=]".
+ - "acc{b ordingly}"
+ - "acc{b ent}" and
+ - "acc{b urate}".
There is no limit on how many groups (with alternation) you can have:
- ```regex
+ 'def LANG regex
+ ```
ac(quirem | c | hievem)en(t | ts)
matches
.bulleted
- - "ac[=quirem=]en[=t=]"
- - "ac[=quirem=]en[=ts=]"
- - "ac[=c=]en[=t=]
- - "ac[=c=]en[=ts=]
- - "ac[=hievem=]en[=t=]" and
- - "ac[=hievem=]en[=ts=]".
+ - "ac{b quirem}en{b t}"
+ - "ac{b quirem}en{b ts}"
+ - "ac{b c}en{b t}
+ - "ac{b c}en{b ts}
+ - "ac{b hievem}en{b t}" and
+ - "ac{b hievem}en{b ts}".
-- [url https://en.wikipedia.org/wiki/Kleene_star Kleene star] - repeat the preceding letter or group, 0 or more times.\n
- An asterisk is used to mark this operation (hence the name, "Kleene [=star=]").
+- {url Kleene star;https://en.wikipedia.org/wiki/Kleene_star} - repeat the preceding letter or group, 0 or more times.\n
+ An asterisk is used to mark this operation (hence the name, "Kleene {b star}").
- ```regex
+ 'def LANG regex
+ ```
accents*
will match
.bulleted
- "accent"
- - "accent[=s=]
- - "accent[=ss=]
- - "accent[=sss=]
+ - "accent{b s}
+ - "accent{b ss}
+ - "accent{b sss}
- and so on
Of course, the asterisk could also be in the middle of the regex, like
- ```regex
+ 'def LANG regex
+ ```
ac*ent
which matches
.bulleted
- "acent"
- - "ac[=c=]ent"
- - "ac[=cc=]ent"
+ - "ac{b c}ent"
+ - "ac{b cc}ent"
- ...
With a group we can repeat entire strings,
- ```regex
+ 'def LANG regex
+ ```
acc(ent)*s
matches
.bulleted
- "accs"
- - "acc[=ent=]s"
- - "acc[=entent=]s
- - "acc[=ententent=]s"
+ - "acc{b ent}s"
+ - "acc{b entent}s
+ - "acc{b ententent}s"
- ...
An alternation allows any alternative to be chosen at any point, so
- ```regex
+ 'def LANG regex
+ ```
acce(n | p)*t
matches
.bulleted
- "accet"
- - "acce[=n=]t
- - "acce[=p=]t
- - "acce[=nn=]t
- - "acce[=np=]t"
- - "acce[=pn=]t"
- - "acce[=pp=]t"
- - "acce[=nnn=]t"
+ - "acce{b n}t
+ - "acce{b p}t
+ - "acce{b nn}t
+ - "acce{b np}t"
+ - "acce{b pn}t"
+ - "acce{b pp}t"
+ - "acce{b nnn}t"
- ...
-In the modern day, regular expressions permit [url https://en.wikipedia.org/wiki/Regular_expression#Syntax additional constructions] like matching the start or end of a string, matching character groups or character classes.
-There are also sometimes features which significantly increase the matching capabilities of normal regexes, like [url https://en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages lookahead and lookbehind assertions].
+In the modern day, regular expressions permit {url additional constructions;https://en.wikipedia.org/wiki/Regular_expression#Syntax} like matching the start or end of a string, matching character groups or character classes.
+There are also sometimes features which significantly increase the matching capabilities of normal regexes, like {url lookahead and lookbehind assertions;https://en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages}.
#### Grammars
@@ -208,89 +212,89 @@ However, even then regular expressions are fairly weak, they can't match recursi
Let's say you want to be able to have math expressions in your language, you can have braces inside braces as much as you like, but in a certain manner:
.bulleted
-- [`1+2`] is a valid expression
-- [`(9-8)+2`] also is valid
-- [`((3*3)-(2^3))+2`] is too
-- however [`()3*3)-(2^3()+2`] isn't valid
+- {` 1+2} is a valid expression
+- {` (9-8)+2} also is valid
+- {` ((3*3)-(2^3))+2} is too
+- however {` ()3*3)-(2^3()+2} isn't valid
-Such a structure is recursive, because it can contain "itself", [`1+2`] can be a standalone math expression, but it can also be contained in another expression, like [`(1+2)*3`], which itself could be inside another bigger expressions and so on.
+Such a structure is recursive, because it can contain "itself", {` 1+2} can be a standalone math expression, but it can also be contained in another expression, like {` (1+2)*3}, which itself could be inside another bigger expressions and so on.
For this task we have a whole separate tool: grammars.
-'footnote terminals-and-nonterminals Formally, we call the rule "names" nonterminals, the idea being that all normal characters, that could appear in our string, are called terminals, since they would terminate replacement and string generation. For the purposes of this post, I won't use the formal names, with the hope that using less terminology will increase understandability.
-
The syntax is different from regexes: a grammar is divided into (production) rules, each rule is named and specifies an expression.
-Expressions are a concatenation of strings and/or names[$terminals-and-nonterminals].
+Expressions are a concatenation of strings and/or names{fn Formally, we call the rule "names" nonterminals, the idea being that all normal characters, that could appear in our string, are called terminals, since they would terminate replacement and string generation. For the purposes of this post, I won't use the formal names, with the hope that using less terminology will increase understandability.}.
Names won't appear in our matched strings, the idea is that a name will be replaced with it's expression, kind of like a placeholders.
Additionally, there can be multiple rules with the same name, meaning a rule can be replaced by different stuff at any point of the string generation.
-'footnote grammar-syntax This is pretty much the mathematical notation, often in CS the Backus-Naur form is used, but I find that a bit harder to read. You might also make the argument that I should use a proper unicode arrow symbol, like [`→`], but [`->`] is way more convinient.
-
Always one name is chosen to be the starting point, and generation continues from there.
-In math literature, generally we write rules in the form [`Name -> Expression`] [$grammar-syntax], and often names are a single capital letter.
-Additionally, often the starting name is called [`S`].
-Finally, in future examples, I'll use the arrow [`⇒`] to show derivations, how the generated string looks after one or two replacements of the name with one of it's expressions.
+In math literature, generally we write rules in the form {` Name -> Expression} {fn This is pretty much the mathematical notation, often in CS the Backus-Naur form is used, but I find that a bit harder to read. You might also make the argument that I should use a proper unicode arrow symbol, like {` →}, but {` ->} is way more convinient.}, and often names are a single capital letter.
+Additionally, often the starting name is called {` S}.
+Finally, in future examples, I'll use the arrow {` ⇒} to show derivations, how the generated string looks after one or two replacements of the name with one of it's expressions.
For an example, with the grammar
-```grammar
+'def LANG grammar
+```
S -> aSb
S -> cc
-we can generate the string [`aaaaccbbbb`] (remember, our starting point is [`S`]):
+we can generate the string {` aaaaccbbbb} (remember, our starting point is {` S}):
-```grammar+
+'def LANG grammar+
+```
S ⇒ aSb ⇒ aaSbb ⇒ aaaSbbb ⇒ aaaaSbbbb ⇒ aaaaccbbbb
-or [`accb`]:
+or {` accb}:
-```grammar+
+'def LANG grammar+
+```
S ⇒ aSb ⇒ accb
where a, b and c are just English characters.
-To simplify our lives, often rules with the same name are merged into one rule, separated by vertical bars ([`S -> aSb | cc`]).
+To simplify our lives, often rules with the same name are merged into one rule, separated by vertical bars ({` S -> aSb | cc}).
This is practically alternation but in a different context.
As for our math expressions, we could create something like this:
-```grammar
+'def LANG grammar
+```
N -> 0 | 1 | 2 | ... all possible numbers
E -> N | (E) | E + E | E - E | E * E | E / E | E ^ E
-which will successfully be able to match (generate) [`((3 * 3) - (2 ^ 3)) + 2`]:
+which will successfully be able to match (generate) {` ((3 * 3) - (2 ^ 3)) + 2}:
-```grammar+
+'def LANG grammar+
+```
E ⇒ E + E ⇒ (E) + N ⇒ (E - E) + 2 ⇒ ((E) - (E)) + 2 ⇒ ((E * E) - (E ^ E)) + 2 ⇒ ((N * N) - (N ^ N)) + 2 ⇒ ((3 * 3) - (2 ^ 3)) + 2
-but there are no expressions (rules) that allow [`()3+3()`] or [`)3(-6`] to be "matched".
+but there are no expressions (rules) that allow {` ()3+3()} or {` )3(-6} to be "matched".
### Lexers and parsers
-You might've noticed that for [`N`] I use three dots and the note "all possible numbers" to signify that N can be any positive whole number.
+You might've noticed that for {` N} I use three dots and the note "all possible numbers" to signify that N can be any positive whole number.
In practice we need formally define that grammar:
-```grammar
+'def LANG grammar
+```
N -> 0 | 1 | 2 | ... | 9 | 0N | 1N | 2N | ... | 9N
-'footnote regular-grammars Such grammars are called [url https://en.wikipedia.org/wiki/Regular_grammar regular grammars], more formally, every rule has to contain at most one name and that name must be at the start or end of the string characters.
-
-With this you might've realised that grammars can do anything a regular expressions can: concatenation and alternation are "built-in", and the Kleene star can be done with another rule in the form [`R -> strR | str`] [$regular-grammars].
+With this you might've realised that grammars can do anything a regular expressions can: concatenation and alternation are "built-in", and the Kleene star can be done with another rule in the form {` R -> strR | str} {fn Such grammars are called {url regular grammars;https://en.wikipedia.org/wiki/Regular_grammar}, more formally, every rule has to contain at most one name and that name must be at the start or end of the string characters.}.
The reason we use both is that grammars are significantly slower and more complicated in code than regexes.
#### Implementational difficulties with grammars
-Implementing (very roughly) the regular expression [`acce(n | p)*t`] is quite easy:
+Implementing (very roughly) the regular expression {` acce(n | p)*t} is quite easy:
-```c++
-'include ./regex_parser_simple.cpp
+```cpp
+'snippet 1 $ ./regex_parser_simple.cpp
In brief, for concatenated characters we do a simple comparison per character.
-When we reach "\_", which I use to specify we're in the [`(n | p)*`] part of the regex, we do comparisons with the characters n and p as much as we can, after which we continue as normal.
+When we reach "\_", which I use to specify we're in the {` (n | p)*} part of the regex, we do comparisons with the characters n and p as much as we can, after which we continue as normal.
Of course, this version only supports one regular expressions, however a "proper" implementation would look conceptually similar: a couple of different loops and equality checks, with maybe an additional array or two.
-The huge benefit is that that loops and arrays are stupid fast, a (simple) C++ for loop could be translated into [url https://godbolt.org/#g:!%28%28g:!%28%28g:!%28%28h:codeEditor,i:%28filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:%28endColumn:16,endLineNumber:6,positionColumn:16,positionLineNumber:6,selectionStartColumn:16,selectionStartLineNumber:6,startColumn:16,startLineNumber:6%29,source:'//+Type+your+code+here,+or+load+an+example.%0Aint+f%28int+num%29+%7B%0A++++for+%28int+i+%3D+1%3B+i+%3C+100%3B+i%2B%2B%29+%7B%0A++++++++num+*%3D+100%3B%0A++++%7D%0A++++return+num%3B%0A%7D'%29,l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0'%29%29,k:50,l:'4',n:'0',o:'',s:0,t:'0'%29,%28g:!%28%28h:compiler,i:%28compiler:g122,deviceViewOpen:'1',filters:%28b:'0',binary:'1',binaryObject:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'%29,flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!%28%29,options:'',selection:%28endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1%29,source:1%29,l:'5',n:'0',o:'+x86-64+gcc+12.2+%28Editor+%231%29',t:'0'%29%29,k:50,l:'4',n:'0',o:'',s:0,t:'0'%29%29,l:'2',n:'0',o:'',t:'0'%29%29,version:4 a handful of processor instructions].
+The huge benefit is that that loops and arrays are stupid fast, a (simple) C++ for loop could be translated into {url a handful of processor instructions;https://godbolt.org/#g:!%28%28g:!%28%28g:!%28%28h:codeEditor,i:%28filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:%28endColumn:16,endLineNumber:6,positionColumn:16,positionLineNumber:6,selectionStartColumn:16,selectionStartLineNumber:6,startColumn:16,startLineNumber:6%29,source:'//+Type+your+code+here,+or+load+an+example.%0Aint+f%28int+num%29+%7B%0A++++for+%28int+i+%3D+1%3B+i+%3C+100%3B+i%2B%2B%29+%7B%0A++++++++num+*%3D+100%3B%0A++++%7D%0A++++return+num%3B%0A%7D'%29,l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0'%29%29,k:50,l:'4',n:'0',o:'',s:0,t:'0'%29,%28g:!%28%28h:compiler,i:%28compiler:g122,deviceViewOpen:'1',filters:%28b:'0',binary:'1',binaryObject:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'%29,flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!%28%29,options:'',selection:%28endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1%29,source:1%29,l:'5',n:'0',o:'+x86-64+gcc+12.2+%28Editor+%231%29',t:'0'%29%29,k:50,l:'4',n:'0',o:'',s:0,t:'0'%29%29,l:'2',n:'0',o:'',t:'0'%29%29,version:4}.
On the other hand, usually grammars are more complicated and resource-intensive.
-Certain ones are simple enough to implement, like [`S -> aSb | cc`]:
+Certain ones are simple enough to implement, like {` S -> aSb | cc}:
```cpp
bool matchesp(string str) {
@@ -302,37 +306,36 @@ bool matchesp(string str) {
return false;
}
-'footnote context-free-grammars Be careful about cases that are too complicated, the grammar I'm showing is "context-free", but that topic is way beyond the scope of this post.
-
-However think about more complicated cases[$context-free-grammars], like [`S -> aSbSa | cc`].
-Implementing this one is quite a bit more difficult, since we don't know where [`b`] is located on the first iteration, it could either be the 4th character [`accb...a`] or the 9th [`aaccbccab...a`].
-Searching for it is also complicated, it could be the first, the last or any other [`b`] in the middle of the string.
+However think about more complicated cases{fn Be careful about cases that are too complicated, the grammar I'm showing is "context-free", but that topic is way beyond the scope of this post.}, like {` S -> aSbSa | cc}.
+Implementing this one is quite a bit more difficult, since we don't know where {` b} is located on the first iteration, it could either be the 4th character {` accb...a} or the 9th {` aaccbccab...a}.
+Searching for it is also complicated, it could be the first, the last or any other {` b} in the middle of the string.
Another difficulty with grammars is ambiguity, let's look at
-```grammar
+'def LANG grammar
+```
E -> E + E | E * E | n
-how would it generate [`n + n * n`]?
+how would it generate {` n + n * n}?
There are two completely valid ways to do so:
-```grammar+
+'def LANG grammar+
+```
E ⇒ E + E ⇒ n + E * E ⇒ n + n * n
-```grammar+
+'def LANG grammar+
+```
E ⇒ E * E ⇒ E + E * n ⇒ n + n * n
How exactly we deal with these problems comes later, for now the takeaway is that we have to try and use regular expressions wherever we can, and leave grammars as a bit of a last resort.
#### Practical usage
-'footnote static-typing Yeah yeah, in a statically typed language you might not be able to do operations on doubles and integers at the same time, but you get the point.
-
Let's think a bit more about grammars: they're really good at handling structure, especially recursive structure, so it's best if we use them only for that.
-Our math expression grammar (from [url #grammars here]) shouldn't really care if we're trying to sum integers or floats or chars[$static-typing], it's important how everything is laid out and that our operations are done with numbers.
+Our math expression grammar (from {url here;#grammars}) shouldn't really care if we're trying to sum integers or floats or chars{fn Yeah yeah, in a statically typed language you might not be able to do operations on doubles and integers at the same time, but you get the point.}, it's important how everything is laid out and that our operations are done with numbers.
-This is why we're going to separate and generalize the code into [url https://en.wikipedia.org/wiki/Lexical_analysis#Token tokens], basically into building blocks.
-As a rough example, we want [`1 + (2 * 3)`] to be transformed into [`NUMBER MATHOP LBRACE NUMBER MATHOP NUMBER RBRACE`], [`int var = 13;`] into [`TYPE NAME ASSIGNMENT NUMBER`] and so on, where "TYPE", "NUMBER", "NAME", ... are tokens.
+This is why we're going to separate and generalize the code into {url tokens;https://en.wikipedia.org/wiki/Lexical_analysis#Token}, basically into building blocks.
+As a rough example, we want {` 1 + (2 * 3)} to be transformed into {` NUMBER MATHOP LBRACE NUMBER MATHOP NUMBER RBRACE}, {` int var = 13;} into {` TYPE NAME ASSIGNMENT NUMBER} and so on, where "TYPE", "NUMBER", "NAME", ... are tokens.
Now we're reducing the amount of "objects" our grammars need to work on: from all characters to many (but significantly fewer) tokens.
Also we're simplifying our work, since we're trying to figure out the overall structure, it doesn't matter if we're multiplying or summing numbers, it's important that we're doing a mathematical operation on them.
Of course, each token will actually be a pair, containing it's name (NUMBER, TYPE, ...) and it's value, but our grammars will work with the names only and output the actual values at the very end.
@@ -340,9 +343,9 @@ Usually we identify at least six token types:
.bulleted
- identifiers: variable and function names for example
-- keywords: [`if`], [`while`], [`for`], [`return`], ...
-- separators: braces, [`;`]
-- operators: [`+`], [`-`], [`<=`]
+- keywords: {` if}, {` while}, {` for}, {` return}, ...
+- separators: braces, {` ;}
+- operators: {` +}, {` -}, {` <=}
- literals: numbers, strings, characters
- comments
@@ -358,8 +361,8 @@ Proper algorithms that "implement" grammars are kind of complicated, and most ca
Generally we categorize them into:
.bulleted
-- [url https://en.wikipedia.org/wiki/Top-down_parsing top-down] algorithms, which work in the way we've been talking about grammars: start with a name and replace it with it's expression, and continue replacements until we have no more names
-- [url https://en.wikipedia.org/wiki/Bottom-up_parsing bottom-up] algorithms, where we do the opposite: for each substring we find from which rule it could've come from, replace it with the corresponding name, and continue upwards like that, until we reach the starting name
+- {url top-down;https://en.wikipedia.org/wiki/Top-down_parsing} algorithms, which work in the way we've been talking about grammars: start with a name and replace it with it's expression, and continue replacements until we have no more names
+- {url bottom-up;https://en.wikipedia.org/wiki/Bottom-up_parsing} algorithms, where we do the opposite: for each substring we find from which rule it could've come from, replace it with the corresponding name, and continue upwards like that, until we reach the starting name
Furthermore, if our algorithms allow for ambiguity (meaning we can replace a name with any one of multiple expressions), we divide them into:
@@ -372,7 +375,7 @@ Looking at some of the more famous ones:
##### LL
-[url https://en.wikipedia.org/wiki/LL_parser LL]: top-down left-most derivations algorithm that can parse only specific types of grammars.
+{url LL;https://en.wikipedia.org/wiki/LL_parser}: top-down left-most derivations algorithm that can parse only specific types of grammars.
In these grammars, every expression is uniquely identifiable by just looking at the characters (tokens) in the very beginning.
The amount of token we need to look for is very important, so we usually define LL(k) as an LL grammar that needs to look at k amount of tokens.
An "LL(k) grammar" is, by extension, a grammar which can be parsed with an LL(k) parser.
@@ -383,57 +386,63 @@ We check the first k character of all expressions, and if anyone of them is a na
:unordered
- As an example, the grammar:
- ```grammar
+ 'def LANG grammar
+ ```
'snippet 1 2 ./grammar_trace_1.txt
is LL(1).
- Let's read the input [`(a + a)`] (the "v" points to the symbol we're looking/peeking at):
+ Let's read the input {` (a + a)} (the "v" points to the symbol we're looking/peeking at):
- ```grammar
+ 'def LANG grammar
+ ```
'snippet 4 8 ./grammar_trace_1.txt
- we start with [`S`], we peek and get the [`(`], in our production we're looking at a name, S.
+ we start with {` S}, we peek and get the {` (}, in our production we're looking at a name, S.
Let's check the first character of every expression of S.
- In the first expression, the first "character" is [`F`], a name, so we look at every expression for [`F`].
+ In the first expression, the first "character" is {` F}, a name, so we look at every expression for {` F}.
There is only one, which is "a", different than "(", no dice.
Now we check the second expression for S, it's first character is "(", success!
We replace:
- ```grammar
+ 'def LANG grammar
+ ```
'snippet 10 14 ./grammar_trace_1.txt
- Now the first symbol in our production is also [`(`], so we increment the symbols we're looking/peeking at
+ Now the first symbol in our production is also {` (}, so we increment the symbols we're looking/peeking at
- ```grammar
+ 'def LANG grammar
+ ```
'snippet 16 20 ./grammar_trace_1.txt
- we peek and get the [`a`], in our production the second "character" is the name [`S`], [`S`] has to become [`a`].
- We do that same check from before, first expression for [`S`] is [`F`], whose first (and only) expression is [`a`], success!
+ we peek and get the {` a}, in our production the second "character" is the name {` S}, {` S} has to become {` a}.
+ We do that same check from before, first expression for {` S} is {` F}, whose first (and only) expression is {` a}, success!
- ```grammar
+ 'def LANG grammar
+ ```
'snippet 22 26 ./grammar_trace_1.txt
- The middle characters " + " are matched and at the second [`F`] we check it's expressions, it has only [`a`], success, replace, end of input, we're done.
+ The middle characters " + " are matched and at the second {` F} we check it's expressions, it has only {` a}, success, replace, end of input, we're done.
- Another LL(1) example can be found in [url http://www.cs.ecu.edu/karl/5220/spr16/Notes/Top-down/LL1.html Karl R. Abrahamson notes].
+ Another LL(1) example can be found in {url Karl R. Abrahamson notes;http://www.cs.ecu.edu/karl/5220/spr16/Notes/Top-down/LL1.html}.
- The grammar
- ```grammar
+ 'def LANG grammar
+ ```
B -> b
C -> c
S -> aaB | aaC
is LL(3).
- For the input [`aab`], if we look at the first two "a"s, we still don't know which rule to use: [`aaB`] or [`aaC`].
- However if we look at the third symbol, "b", then we can determine that we need [`aaB`].
+ For the input {` aab}, if we look at the first two "a"s, we still don't know which rule to use: {` aaB} or {` aaC}.
+ However if we look at the third symbol, "b", then we can determine that we need {` aaB}.
-- Usually parsers that implement this procedure are called [url https://en.wikipedia.org/wiki/Recursive_descent_parser recursive descent parsers]
+- Usually parsers that implement this procedure are called {url recursive descent parsers;https://en.wikipedia.org/wiki/Recursive_descent_parser}
##### LR
-[url https://en.wikipedia.org/wiki/LR_parser LR]: bottom-up right-most derivations algorithm.
+{url LR;https://en.wikipedia.org/wiki/LR_parser}: bottom-up right-most derivations algorithm.
Conceptually, LR works in the exact opposite way to LL: for every character in the input, we find a rule that substitutes it (or that substitutes the current collection of names and character) and do so until we've reached the starting name.
Figuring out an approach isn't as intuitive and easy as with LL, but it still isn't too hard.
@@ -442,7 +451,8 @@ It all boils down to using a whole bunch of conditional statements and tracing w
:unordered
- Let's look at the first LL example:
- ```grammar
+ 'def LANG grammar
+ ```
'snippet 1 2 ./grammar_trace_2.txt
We need to track the current state of the string, because imagine we've just read an "a", it could either be from the left or right handside of "a + a", and that changes what character to expect next.
@@ -454,9 +464,9 @@ It all boils down to using a whole bunch of conditional statements and tracing w
|: 0
|: Nothing; this is the start
|: 1
- |: The name [`S`]; the final number should be this
+ |: The name {` S}; the final number should be this
|: 2
- |: The name [`F`]
+ |: The name {` F}
|: 3
|: The character "("
|: 4
@@ -504,7 +514,7 @@ It all boils down to using a whole bunch of conditional statements and tracing w
'snippet 16 17 ./grammar_trace_2.txt
We have a different state for "(S", because if we didn't, we would've gone to state 1, and could've ended the algorithm then and there, without reading the rest of the input.
- Otherwise, we continue as normal, we read the [`+`] and the spaces around it, going to state 6.
+ Otherwise, we continue as normal, we read the {` +} and the spaces around it, going to state 6.
```
'snippet 19 20 ./grammar_trace_2.txt
@@ -577,7 +587,7 @@ It all boils down to using a whole bunch of conditional statements and tracing w
- You're probably wondering why the table works so weird, like why on state 3 we don't directly replace "a" with "S" and change to state 5 for example.
The reason is that the way I showed the algorithm isn't exactly how it normally works.
- Rather than tracing the current state in a variable, we trace it with a [url https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 stack].
+ Rather than tracing the current state in a variable, we trace it with a {url stack;https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29}.
When you read a character and have to go to another state, the state is added to the stack (this operation is called "shift").
When we have to change characters from String (without reading anything), with a string (expression) of length j, we remove the last j added states and do a normal shift from the last state and character in String (this operation is called "reduce").
@@ -615,27 +625,27 @@ It all boils down to using a whole bunch of conditional statements and tracing w
This way we avoid doing different things on different states and we don't need to store the whole string, only the last few characters.
Additionally, in the real world nobody makes this table by hand, it is generated by a program, and this method makes table generation easier.
-- As for the complete table, you can view it on the [url https://smlweb.cpsc.ucalgary.ca/lr0.php?grammar=S+-%3E+F+%7C+%28+S+%2B+F+%29.%0AF+-%3E+a.&substs= Context Free Grammar Checker],\n
- or with a more pretty styling on [url https://mdaines.github.io/grammophone/?s=UyAtPiBGIHwgIigiIFMgIisiIEYgIikiLgpGIC0+IGEu#/ Grammophone], opening "Parsing table" on the row "LR(0)".
+- As for the complete table, you can view it on the {url Context Free Grammar Checker;https://smlweb.cpsc.ucalgary.ca/lr0.php?grammar=S+-%3E+F+%7C+%28+S+%2B+F+%29.%0AF+-%3E+a.&substs=},\n
+ or with a more pretty styling on {url Grammophone;https://mdaines.github.io/grammophone/?s=UyAtPiBGIHwgIigiIFMgIisiIEYgIikiLgpGIC0+IGEu#/}, opening "Parsing table" on the row "LR(0)".
To read the table, remember that:
.bulleted
- on every row you have each state
- on every column you have each possible value in the string and "$" which signifies the end of the string
- - with [`sr`] or [`shift`] (or just with a number) you go to another state
- - with [`r`] or [`reduce`] you make the substitution in the current string and go back one state
- - [`acc`] or [`accept`] means you've reached the end and the string is valid
+ - with {` sr} or {` shift} (or just with a number) you go to another state
+ - with {` r} or {` reduce} you make the substitution in the current string and go back one state
+ - {` acc} or {` accept} means you've reached the end and the string is valid
##### LR's family
LR is more of a family of algorithms, because there are multiple different ways to generate the table, each with it's own benefits and drawbacks.
This subject is a really big can of beans, which I'm not knowledgeable enough to talk about.
-What you need to know is that there are 3 often used types: [url https://en.wikipedia.org/wiki/Canonical_LR_parser CLR], [url https://en.wikipedia.org/wiki/Simple_LR_parser SLR] and [url https://en.wikipedia.org/wiki/LALR_parser LALR].
+What you need to know is that there are 3 often used types: {url CLR;https://en.wikipedia.org/wiki/Canonical_LR_parser}, {url SLR;https://en.wikipedia.org/wiki/Simple_LR_parser} and {url LALR;https://en.wikipedia.org/wiki/LALR_parser}.
.bulleted
-- CLR is an LR parser with 1 character lookahead (LR(1)), following [url TODO Knuth]'s original theory.
+- CLR is an LR parser with 1 character lookahead (LR(1)), following {url Knuth;TODO}'s original theory.
It requires a lot of memory for table generation, so Frank DeRemer created two simplifications:
- the SLR and LALR, which use significantly less memory but work with a bit less grammars
@@ -646,28 +656,26 @@ LALR is the most commonly used LR parser, however most compilers are custom-tail
If you want to learn more, I would highly suggest:
.bulleted
-- [url https://blog.reverberate.org/2013/07/ll-and-lr-parsing-demystified.html LL and LR Parsing Demystified] and [url https://blog.reverberate.org/2013/09/ll-and-lr-in-context-why-parsing-tools.html LL and LR in Context: Why Parsing Tools Are Hard] by [url https://blog.reverberate.org/about/ Josh Haberman]
-- [url http://jeffreykegler.github.io/Ocean-of-Awareness-blog/individual/2014/11/ll.html Parsing: Top-down versus bottom-up] by [url https://jeffreykegler.github.io/personal/ Jeffrey Kegler]
-- [url https://tratt.net/laurie/blog/2020/which_parsing_approach.html Which Parsing Approach?] by [url https://tratt.net/laurie/ Laurence Tratt]
-- [url https://tomassetti.me/guide-parsing-algorithms-terminology/ A Guide to Parsing: Algorithms and Terminology] by [url https://inre.me/ Gabriele Tomassetti]
-- [url http://www.cs.ecu.edu/karl/5220/spr16/Notes/Parsing/index.html Parsing], [url http://www.cs.ecu.edu/karl/5220/spr16/Notes/Top-down/index.html Top-Down Parsers] and [url http://www.cs.ecu.edu/karl/5220/spr16/Notes/Bottom-up/index.html Bottom-Up Parsers] from [url http://www.cs.ecu.edu/karl/5220/spr16/Notes/Bottom-up/index.html Karl R. Abrahamson]'s notes
-- [url https://serokell.io/blog/how-to-implement-lr1-parser How to Impement an LR(1) Parser] by Kirill Andreev
+- {url LL and LR Parsing Demystified;https://blog.reverberate.org/2013/07/ll-and-lr-parsing-demystified.html} and {url LL and LR in Context: Why Parsing Tools Are Hard;https://blog.reverberate.org/2013/09/ll-and-lr-in-context-why-parsing-tools.html} by {url Josh Haberman;https://blog.reverberate.org/about/}
+- {url Parsing: Top-down versus bottom-up;http://jeffreykegler.github.io/Ocean-of-Awareness-blog/individual/2014/11/ll.html} by {url Jeffrey Kegler;https://jeffreykegler.github.io/personal/}
+- {url Which Parsing Approach?;https://tratt.net/laurie/blog/2020/which_parsing_approach.html} by {url Laurence Tratt;https://tratt.net/laurie/}
+- {url A Guide to Parsing: Algorithms and Terminology;https://tomassetti.me/guide-parsing-algorithms-terminology/} by {url Gabriele Tomassetti;https://inre.me/}
+- {url Parsing;http://www.cs.ecu.edu/karl/5220/spr16/Notes/Parsing/index.html}, {url Top-Down Parsers;http://www.cs.ecu.edu/karl/5220/spr16/Notes/Top-down/index.html} and {url Bottom-Up Parsers;http://www.cs.ecu.edu/karl/5220/spr16/Notes/Bottom-up/index.html} from {url Karl R. Abrahamson;http://www.cs.ecu.edu/karl/5220/spr16/Notes/Bottom-up/index.html}'s notes
+- {url How to Impement an LR(1) Parser;https://serokell.io/blog/how-to-implement-lr1-parser} by Kirill Andreev
#### Abstract syntax tree
We already decided that the lexer will output tokens (and characters) to the parser, but we didn't talk about what the parser is supposed to output.
-It definitely has to be some sort of structural representation of the overall code, for example, for [`3 + 1 * 2`] we have to be able to easily find out what the left and right handsides of the [`+`] and [`*`] are.
-
-'footnote nomnoml The graphics are made with [url https://nomnoml.com/ nomnoml] by [url https://github.com/skanaar Daniel Kallin]
+It definitely has to be some sort of structural representation of the overall code, for example, for {` 3 + 1 * 2} we have to be able to easily find out what the left and right handsides of the {` +} and {` *} are.
-Let's draw out[$nomnoml] this relationship, where the left arrow connects to the left handside and the right accordingly:
+Let's draw out{fn The graphics are made with {url nomnoml;https://nomnoml.com/} by {url Daniel Kallin;https://github.com/skanaar}} this relationship, where the left arrow connects to the left handside and the right accordingly:
-[image ./img/tree-simple.svg]
+{img ./img/tree-simple.svg}
-Hey, that looks an awful lot like a [url https://en.wikipedia.org/wiki/Tree_%28data_structure%29 tree]!
-Trees are nodes, some sort of elements, where there is a connection from one element to some other elements, with the only rule being that cycles [=aren't=] allowed:
+Hey, that looks an awful lot like a {url tree;https://en.wikipedia.org/wiki/Tree_%28data_structure%29}!
+Trees are nodes, some sort of elements, where there is a connection from one element to some other elements, with the only rule being that cycles {b aren't} allowed:
-[image ./img/tree-cycle.svg]
+{img ./img/tree-cycle.svg}
Great, but can we represent everything else with a tree?
Why, of course, for example we can represent:
@@ -680,130 +688,134 @@ else
as
-[image ./img/tree-if.svg]
+{img ./img/tree-if.svg}
You might ask how we generate the tree, and the answer is simple: on every step we add nodes to the tree, depending on the situation.
Let's look at a familiar example:
-```grammar
+'def LANG grammar
+```
N -> 1 | 2 | 3
E -> N | (E) | E + E | E * E
-Let's look at the input string [`2 * (1 + 3)`], while abstracting ourselves from any particular algorithm:
+Let's look at the input string {` 2 * (1 + 3)}, while abstracting ourselves from any particular algorithm:
:unordered
-- we read the [`2`], that is a number, we add it as a node
+- we read the {` 2}, that is a number, we add it as a node
- .p [image ./img/tree-building-1.svg]
+ .p {img ./img/tree-building-1.svg}
-- then we read the [`*`], we now know our expression is in the form [`E* E`].
+- then we read the {` *}, we now know our expression is in the form {` E* E}.
If you think about it, up to this point, we've basically been building a tree for the left handside.
- [=If=] the topmost element in that tree is a brace,
+ {b If} the topmost element in that tree is a brace,
- .p [image ./img/tree-building-ex1.svg]
+ .p {img ./img/tree-building-ex1.svg}
- we connect it to the left handside of [`*`]:
+ we connect it to the left handside of {` *}:
- .p [image ./img/tree-building-ex2.svg]
+ .p {img ./img/tree-building-ex2.svg}
- [=Otherwise=] (when it's [`+`] or [`*`] or a number), because of precedence, we'll attach the latest number to the left handside.
- However we have to be careful, if something connects to the number, we now need it to connect to the [`*`].\n
- For example, let's say we had [`1 + 2 * 3`], and we've just read the [`*`].
+ {b Otherwise} (when it's {` +} or {` *} or a number), because of precedence, we'll attach the latest number to the left handside.
+ However we have to be careful, if something connects to the number, we now need it to connect to the {` *}.\n
+ For example, let's say we had {` 1 + 2 * 3}, and we've just read the {` *}.
The tree up to this point would look like,
- .p [image ./img/tree-building-ex3.svg]
+ .p {img ./img/tree-building-ex3.svg}
- where the latest number we've found was [`2`], but the [`+`] connects to it.
- So, we need to make the [`2`] connect to the left handside of [`*`], and make [`+`] connect to [`*`] instead of [`2`]
+ where the latest number we've found was {` 2}, but the {` +} connects to it.
+ So, we need to make the {` 2} connect to the left handside of {` *}, and make {` +} connect to {` *} instead of {` 2}
- .p [image ./img/tree-building-ex4.svg]
+ .p {img ./img/tree-building-ex4.svg}
- In our original case, nothing connects to the [`2`] in [`2 * (1 + 3)`], so we can just connect it to the left handside of [`*`]
+ In our original case, nothing connects to the {` 2} in {` 2 * (1 + 3)}, so we can just connect it to the left handside of {` *}
- .p [image ./img/tree-building-2.svg]
+ .p {img ./img/tree-building-2.svg}
where the three dots signify there isn't anything there (but we expect there to be).
Somewhere we'll store that the next element we find has to be connected to the right handside.
-- now we read [`(`], we cannot have it by itself, so we directly decide we're working with [`(E)`] (in our full algorithm we would need a check for existance of matching brace).
- We'll create a [`()`] node and because of the last step, we'll connect it to the right handside.
+- now we read {` (}, we cannot have it by itself, so we directly decide we're working with {` (E)} (in our full algorithm we would need a check for existance of matching brace).
+ We'll create a {` ()} node and because of the last step, we'll connect it to the right handside.
- .p [image ./img/tree-building-3.svg]
+ .p {img ./img/tree-building-3.svg}
- Now, moving forward, we'll be creating a subtree, essentially making a second tree, and after that is done, we'll connect it's topmost element (root) to the [`()`] node.
+ Now, moving forward, we'll be creating a subtree, essentially making a second tree, and after that is done, we'll connect it's topmost element (root) to the {` ()} node.
- and so on.
The overall algorithm is to add and change nodes every time you match something with a grammar rule, and the adding and changing is done, depending on the language, the current structure and so on.
-When discussing the middle and back-end layers, we'll talk about how to work with a generated AST, but for now your clue is the [url https://en.wikipedia.org/wiki/Visitor_pattern visitor pattern].
+When discussing the middle and back-end layers, we'll talk about how to work with a generated AST, but for now your clue is the {url visitor pattern;https://en.wikipedia.org/wiki/Visitor_pattern}.
### Implementing a front-end
If you want, you could implement your own lexer and parser manually, but as a start, it's worthwhile to try and use already created stuff.
-[url https://en.wikipedia.org/wiki/Compiler-compiler Compiler-compilers] are tools that create parsers (and more) from their normal formal definition.
+{url Compiler-compilers;https://en.wikipedia.org/wiki/Compiler-compiler} are tools that create parsers (and more) from their normal formal definition.
The two popular ones from the old days are lex and yacc.
lex is a lexer generator and yacc is a LALR parser generator, both of which generate a corresponding C implementation of the given regular expressions and grammars.
#### lex
-Lex is the original program, from 1975, in the modern day it's successor/implementation is the open-source [url https://github.com/westes/flex flex].
+Lex is the original program, from 1975, in the modern day it's successor/implementation is the open-source {url flex;https://github.com/westes/flex}.
A lex source file is divided into three parts:
-```lex
-'include ./template.l
+'def LANG lex
+```
+'snippet 1 $ ./template.l
-where [`%{%}`] is used for includes and declarations, the rules are your regular expressions and the C code is the general logic of the lexer.
-Usually you wouldn't write anything in the C code section, the defaults are fine, but you'll probably need to do one or two includes in the [`%{%}`] section.
+where {` %{%}} is used for includes and declarations, the rules are your regular expressions and the C code is the general logic of the lexer.
+Usually you wouldn't write anything in the C code section, the defaults are fine, but you'll probably need to do one or two includes in the {` %{%}} section.
-Rules are in the form [`regex { C_code }`].
+Rules are in the form {` regex { C_code }}.
To simplify your life, you can write only the regex or a part of it inside the "definitions" part of the file, and give it a name to use later.
Referencing those names in later regexes is done by surrounding them in curly braces.
-Usually the [`C_code`] in the regex would be a return (more commonly called "emit") of a token, which will be available in a header file, but more on that later.
+Usually the {` C_code} in the regex would be a return (more commonly called "emit") of a token, which will be available in a header file, but more on that later.
Let's look at a very simple example program: every whole number is printed as "NUMBER", while everything else is printed as-is:
-```lex
-'include ./example_lex/lexer.l
+'def LANG lex
+```
+'snippet 1 $ ./example_lex/lexer.l
-The syntax [`[0-9]`] is the same as [`(0 | 1 | ... | 9)`], it works for any letters and is available in all modern regexes.
-Note that inside every regex's "body" you have an assortment of variables already set, one of them being [`yytext`] which is just the whole match.
-Additionally lex matches the longest possible match, so if we had a rule [`[0-z]`], only it will be matched.
+The syntax {` [0-9]} is the same as {` (0 | 1 | ... | 9)}, it works for any letters and is available in all modern regexes.
+Note that inside every regex's "body" you have an assortment of variables already set, one of them being {` yytext} which is just the whole match.
+Additionally lex matches the longest possible match, so if we had a rule {` [0-z]}, only it will be matched.
-If this file is located in [`lexer.l`], we can transform it into a C file with:
+If this file is located in {` lexer.l}, we can transform it into a C file with:
```bash
flex lexer.l
-Usually the result file is always named [`lex.yy.c`].
+Usually the result file is always named {` lex.yy.c}.
Afterwards, we can compile the C code into a working compiler:
```bash
gcc lex.yy.c -lfl
-Without the [`-lfl`] flag, we would get a linking error, because of the [`main`] and [`yywrap`] function, which are required but aren't defined in our generated code.
+Without the {` -lfl} flag, we would get a linking error, because of the {` main} and {` yywrap} function, which are required but aren't defined in our generated code.
There are three ways to fix this problem:
:numbered
-1. The one I've opted for, use the [`-lfl`] flag to compile our C code with a (flex) library which provides both functions.
- Usually the lexer isn't meant to be ran by itself, so for the current time being, [`-lfl`] is the best option, the other two are fine when we get to [`yacc`].
+1. The one I've opted for, use the {` -lfl} flag to compile our C code with a (flex) library which provides both functions.
+ Usually the lexer isn't meant to be ran by itself, so for the current time being, {` -lfl} is the best option, the other two are fine when we get to {` yacc}.
-2. Put [`%option noyywrap`] in the definitions section, which means the lexer will only read one file.
+2. Put {` %option noyywrap} in the definitions section, which means the lexer will only read one file.
3. Define it ourselves.
It should return 0 if our lexer should continue with the next given file, after finishing with the current one, or 1 if it should stop execution.
The function could be written in either "C code" section, but I personally prefer the last one.
- ```lex
+ 'def LANG lex
+ ```
int yywrap() { return 0; }
Of course, you can use your lex implementation or C compiler of choice, and there this might not be a problem.
-Now, if you run [`./a.out`] you would get a prompt, every line you write will be lexically analyzed and in our case, everything will be printed out.
+Now, if you run {` ./a.out} you would get a prompt, every line you write will be lexically analyzed and in our case, everything will be printed out.
Entering
```
@@ -827,8 +839,9 @@ and strings:
We'll define numbers as both whole digits and floating point numbers (with sign) and strings can be surrounded in either single or double quotes.
-```lex
-'include ./example_lex/numbers_html.l
+'def LANG lex
+```
+'snippet 1 $ ./example_lex/numbers_html.l
With the input
@@ -841,45 +854,50 @@ we'll get
John said <span class="num">10</span> times <span class="str">"2 + 2 = 5"</span> but <span class="str">'2 + 2 = 4'</span>!
You've probably already noticed that the number inside the strings aren't matched, because the string rule results in a longer match.
-In certain programming languages, that don't have [url https://en.wikipedia.org/wiki/String_interpolation string interpolation] this is fine, but for others our regexes have to be a lot more complicated.
+In certain programming languages, that don't have {url string interpolation;https://en.wikipedia.org/wiki/String_interpolation} this is fine, but for others our regexes have to be a lot more complicated.
#### yacc
-Similarly to lex, yacc originates from 1975, and it's modern replacement is [url https://www.gnu.org/software/bison/ GNU Bison].
+Similarly to lex, yacc originates from 1975, and it's modern replacement is {url GNU Bison;https://www.gnu.org/software/bison/}.
A yacc file looks very similarly to a lex one:
-```yacc
-'include ./template.y
+'def LANG yacc
+```
+'snippet 1 $ ./template.y
however rather than definitions you have declarations, and the rules are in a completely different format (because they're grammars).
-Token names are defined in [`declarations`], in the format
+Token names are defined in {` declarations}, in the format
-```yacc
+'def LANG yacc
+```
%token NAME1 NAME2 ...
-You can also define precedence with [`%left`] and [`%right`].
-There are also other options you can set, like the start name with [`%start`].
+You can also define precedence with {` %left} and {` %right}.
+There are also other options you can set, like the start name with {` %start}.
Grammars are in the form
-```yacc
+'def LANG yacc
+```
name : TOKEN1 TOKEN2 ...
;
where alternation is defined like
-```yacc
+'def LANG yacc
+```
name : TOKEN1
| TOKEN2
| TOKEN3
;
-and it always must end with a [`;`].
+and it always must end with a {` ;}.
On each alternation, you can (should) specify a body, which will contain C code to be executed, if this rule is reached
-```yacc
+'def LANG yacc
+```
name : TOKEN1 { C code here }
| TOKEN2
| TOKEN3 { C code here }
@@ -887,38 +905,40 @@ name : TOKEN1 { C code here }
Another difference is that, since the parser needs a list of tokens, you cannot run it by itself, you'll also need to setup a lexer.
-'footnote shift-reduce-conflicts You might be tempted to try and make one for the grammar inside the [url #abstract-syntax-tree AST] section, but that one is ever so slightly problematic, because it's ambiguous (I showed why at the end of [url #implementational-difficulties-with-grammars Implementational difficulties with grammars]). Bison [url https://www.gnu.org/software/bison/manual/html_node/Shift_002fReduce.html can handle ambiguity by always choosing to shift], but I didn't want to complicate things.
+Let's implement a parser for the grammar{fn You might be tempted to try and make one for the grammar inside the {url AST;#abstract-syntax-tree} section, but that one is ever so slightly problematic, because it's ambiguous (I showed why at the end of {url Implementational difficulties with grammars;#implementational-difficulties-with-grammars}). Bison {url can handle ambiguity by always choosing to shift;https://www.gnu.org/software/bison/manual/html_node/Shift_002fReduce.html}, but I didn't want to complicate things.}:
-Let's implement a parser for the grammar[$shift-reduce-conflicts]:
-
-```grammar
+'def LANG grammar
+```
N -> 1 | 2 | 3
S -> N | (S + S) | (S * S)
First, our tokens, we want to replace all characters with a token.
-For 1, 2 and 3, let's use the token name "NUMBER", for "(" and ")", LBRACE and RBRACE accordingly, and since there is no precedence with this grammar, we don't actually care if we have [`(S + S)`] or [`(S * S)`], so we can assign both [`+`] and [`*`] to the token MATHOP.
+For 1, 2 and 3, let's use the token name "NUMBER", for "(" and ")", LBRACE and RBRACE accordingly, and since there is no precedence with this grammar, we don't actually care if we have {` (S + S)} or {` (S * S)}, so we can assign both {` +} and {` *} to the token MATHOP.
Meaning, our grammar would behave more like this:
-```grammar
+'def LANG grammar
+```
N -> 1 | 2 | 3
M -> + | *
S -> N | (S M S)
-First, we need to make our [`lexer.l`], it is going to be very simple:
+First, we need to make our {` lexer.l}, it is going to be very simple:
-```lex
-'include ./example_yacc/lexer.l
+'def LANG lex
+```
+'snippet 1 $ ./example_yacc/lexer.l
Now, tokens (names) are defined inside grammars, however our lexer needs to emit (return) them.
-That's why, when running bison on our [`parser.y`], we'll also create a C header file, which contains those names already defined, so they're accessible inside [`lexer.l`].
-This file is in the format [`FILENAME.tab.h`], where [`FILENAME.y`] is our source yacc file.
+That's why, when running bison on our {` parser.y}, we'll also create a C header file, which contains those names already defined, so they're accessible inside {` lexer.l}.
+This file is in the format {` FILENAME.tab.h}, where {` FILENAME.y} is our source yacc file.
-Second, we need to make our [`parser.y`]:
+Second, we need to make our {` parser.y}:
-```yacc
-'include ./example_yacc/parser.y
+'def LANG yacc
+```
+'snippet 1 $ ./example_yacc/parser.y
-A quirk with GNU Bison is that you need to declare the function [`yylex`] and [`yyerror`] beforehand, manually define [`yyerror`] and run [`yyparse`] in the main function.
+A quirk with GNU Bison is that you need to declare the function {` yylex} and {` yyerror} beforehand, manually define {` yyerror} and run {` yyparse} in the main function.
These are precisely the first 5 and the last 8 lines of code, but for now you don't need to think about them.
Let's get to compiling.
@@ -932,13 +952,13 @@ then our parser:
```bash
bison -d parser.y
-where the [`-d`] option means we'll also output the [`parser.tab.h`] header file.
+where the {` -d} option means we'll also output the {` parser.tab.h} header file.
Finally, we compile both of them together into one executable:
```bash
gcc lex.yy.c parse.tab.c -lfl
-Now when you run [`./a.out`], if you enter a valid string, you'll see a blank line, but if it isn't valid, you'll get "Error: syntax error".
+Now when you run {` ./a.out}, if you enter a valid string, you'll see a blank line, but if it isn't valid, you'll get "Error: syntax error".
#### Doing it properly
@@ -946,23 +966,25 @@ The way we created that lexer and parser worked, but it wasn't very useful and h
:ordered
1. When entering a string that isn't matched at all, it gets printed back like nothing happened.
- For example, if we enter the letter [`a`] or any string which doesn't have [`(`], [`)`], [`1`], [`2`], [`3`], [`+`] or [`-`] characters, it will just get printed back.
- Ideally, we want to raise an error, so we're going to add one rule which catches any (non-special) character and throws an error with the built-in [`yy_fatal_error`]:
+ For example, if we enter the letter {` a} or any string which doesn't have {` (}, {` )}, {` 1}, {` 2}, {` 3}, {` +} or {` -} characters, it will just get printed back.
+ Ideally, we want to raise an error, so we're going to add one rule which catches any (non-special) character and throws an error with the built-in {` yy_fatal_error}:
- ```lex
+ 'def LANG lex
+ ```
. { yy_fatal_error("Bad character"); }
This rule must be the last rule, since we don't want it to be matched, if there is another rule that matches.
Remember that lex matches the longest possible string and if there are multiple rules which match the same amount of characters, only the first one is matched.
2. For every token name, returned by the lexer, we also need to have it's actual value.
- We could make a [`struct`], which holds both a token name and it's value, but there is another [url https://www.gnu.org/software/bison/manual/html_node/Token-Values.html "built-in" mechanism] for that in yacc/Bison.
- We would set the global variable [`yylval`] to the token value, and it will be changed for every token.
+ We could make a {` struct}, which holds both a token name and it's value, but there is another {url "built-in" mechanism;https://www.gnu.org/software/bison/manual/html_node/Token-Values.html} for that in yacc/Bison.
+ We would set the global variable {` yylval} to the token value, and it will be changed for every token.
- By default it's type is [`int`] (in Bison), but usually you would want it to be a [url https://en.wikipedia.org/wiki/Union_type#C/C++ union].
+ By default it's type is {` int} (in Bison), but usually you would want it to be a {url union;https://en.wikipedia.org/wiki/Union_type#C/C++}.
Let's make it a union of int and char, though the first part is kind of useless, since we're only working with single digit numbers.
\n
- ```yacc
+ 'def LANG yacc
+ ```
%union {
int num;
char chr;
@@ -970,73 +992,80 @@ The way we created that lexer and parser worked, but it wasn't very useful and h
Now, inside our lexer, rules would look like:
- ```yacc
+ 'def LANG yacc
+ ```
RULE1 { yylval.num = 129; return TOKEN; }
RULE2 { yylval.chr = 'a'; return TOKEN; }
- Inside C blocks for grammar rules we can reference the token values with [`\$i`], where [`i`] is the i'th "token" in the expression.
- For example, in this rule, [`\$1`] would be [`(`], [`\$3`] would be value of token [`B`] and [`\$5`] would be the value of the rule name:
+ Inside C blocks for grammar rules we can reference the token values with {` \$i}, where {` i} is the i'th "token" in the expression.
+ For example, in this rule, {` \$1} would be {` (}, {` \$3} would be value of token {` B} and {` \$5} would be the value of the rule name:
- ```yacc
+ 'def LANG yacc
+ ```
rule : ( A B ) rule
;
- You can set rule "return" values by setting the variable [`\$$`]:
+ You can set rule "return" values by setting the variable {` \$$}:
- ```yacc
+ 'def LANG yacc
+ ```
rule : LBRACE rule RBRACE { $$ = 10; }
The way you set it's type is discussed later.
- However, [`\$i`] isn't of type union, we cannot do something like [`\$i.num`], it is the precise value that was set for the token.
- Therefore, we also need to define which value from the union every token will set, which is done by adding [`<PROPERTY>`] before every defined token (and [`PROPERTY`] is a property name inside the union):
+ However, {` \$i} isn't of type union, we cannot do something like {` \$i.num}, it is the precise value that was set for the token.
+ Therefore, we also need to define which value from the union every token will set, which is done by adding {` <PROPERTY>} before every defined token (and {` PROPERTY} is a property name inside the union):
- ```yacc
+ 'def LANG yacc
+ ```
%token <num> NUMBER <chr> MATHOP <chr> LBRACE <chr> RBRACE
- 'footnote better-bison-errors You can add [`%define parse.error verbose`] inside definitions of your yacc file, and it will tell you what character was expected and what character was read.
-
-3. If we enter one valid math expression, we'll get no error, but when we enter another, we'll get a "syntax error"[$better-bison-errors].
+3. If we enter one valid math expression, we'll get no error, but when we enter another, we'll get a "syntax error"{fn You can add {` %define parse.error verbose} inside definitions of your yacc file, and it will tell you what character was expected and what character was read.}.
That is because we try to match only one expression, after it is matched our parser is waiting for an end of file character.
Let's make it so we would try to match an expression on every line:
- ```yacc
+ 'def LANG yacc
+ ```
start : expr
| expr start
;
- A rule like [`expr : expr expr`] will produce shift/reduce conflicts.
- Another option is duplicating our [`expr`] rules and adding [`expr`] in the beginning or end, but that is cumbersome if we want to make changes.
+ A rule like {` expr : expr expr} will produce shift/reduce conflicts.
+ Another option is duplicating our {` expr} rules and adding {` expr} in the beginning or end, but that is cumbersome if we want to make changes.
4. We're getting input from the user, but our source text (code) will be in a file.
- First, our [`main`] function needs to take program parameters:
+ First, our {` main} function needs to take program parameters:
- ```yacc
+ 'def LANG yacc
+ ```
int main(int argc, char* argv[])
Then we need to take the first argument, and open a file.
Additionally, we have to check if the file was successfully opened, and print an error and stop execution if so:
- ```yacc
+ 'def LANG yacc
+ ```
FILE* input = fopen(argv[1], "r");
if (input == NULL) {
yyerror("cannot read input file!");
return 1;
}
- Now for the clever bit, actual parsing in generated code is done on the file [`yyin`], which by default is the standard user input.
+ Now for the clever bit, actual parsing in generated code is done on the file {` yyin}, which by default is the standard user input.
To read a file, all we need to do is change the value of that variable.
Also, that variable is defined externally, so first we need to add to (the top) C section:
- ```yacc
+ 'def LANG yacc
+ ```
extern FILE* yyin;
- and then put in our [`main`]:
+ and then put in our {` main}:
- ```yacc
+ 'def LANG yacc
+ ```
yyin = input;
- On \*NIX systems (Linux, MacOS, OpenBSD, ...) you can still use user input by passing the file [`/dev/stdin`].
- If you want your front-end to support multiple files, you would just need to wrap the whole body of main in a [`for`] loop, iterating over the whole [`argv`] array (remember that [`argc`] is the length of the array).
+ On \*NIX systems (Linux, MacOS, OpenBSD, ...) you can still use user input by passing the file {` /dev/stdin}.
+ If you want your front-end to support multiple files, you would just need to wrap the whole body of main in a {` for} loop, iterating over the whole {` argv} array (remember that {` argc} is the length of the array).
5. We need to construct an AST.
Since the exact tree structure depends on your needs, I'll make the simplest possible tree in pure C that works for this grammar.
@@ -1047,47 +1076,49 @@ yyin = input;
#include <stdio.h>
'snippet 2 $ ./proper/tree.c
- However, all of this is quite a lot, and it would take a lot of space in [`parser.y`], so let's separate it into [`tree.c`] and add a header file [`tree.h`] which contains the definitions:
+ However, all of this is quite a lot, and it would take a lot of space in {` parser.y}, so let's separate it into {` tree.c} and add a header file {` tree.h} which contains the definitions:
```c
'snippet 4 15 ./proper/tree.h
Of course, we should add some ifndef-def precompiler code, but that isn't relevant for now.
- The way we're going to use trees in our grammar is as follows: for the [`NUMBER`] expression of [`expr`], we'll create a node with the (char) value of the number and "return" it.
- For the expression of [`expr`] we'll "return" a node with the value of the math operator and left and right will be the returned values.
- Inside start, after we've parsed an [`expr`], we'll print out the "returned" tree and free it's memory.
+ The way we're going to use trees in our grammar is as follows: for the {` NUMBER} expression of {` expr}, we'll create a node with the (char) value of the number and "return" it.
+ For the expression of {` expr} we'll "return" a node with the value of the math operator and left and right will be the returned values.
+ Inside start, after we've parsed an {` expr}, we'll print out the "returned" tree and free it's memory.
- I'm putting returned in quotes, because (as mentioned), we'll just be setting the value of [`\$$`].
- [`\$$`]'s type is set with the [`%type`] option, which works exactly like [`%token`], but with grammar rule names.
- However, this means that [`node`] must be available in [`%union`], which is unfortunate but isn't a problem, we'll just add it.
+ I'm putting returned in quotes, because (as mentioned), we'll just be setting the value of {` \$$}.
+ {` \$$}'s type is set with the {` %type} option, which works exactly like {` %token}, but with grammar rule names.
+ However, this means that {` node} must be available in {` %union}, which is unfortunate but isn't a problem, we'll just add it.
- Now, finally, it's time to include our [`tree.h`] in [`parser.y`], but we'll also need to include it in [`lexer.l`].
- The reason is that the [`%union`] appears in [`parser.tab.h`], which means our node structure is referenced in [`parser.tab.h`], but [`tree.h`] isn't included there.
+ Now, finally, it's time to include our {` tree.h} in {` parser.y}, but we'll also need to include it in {` lexer.l}.
+ The reason is that the {` %union} appears in {` parser.tab.h}, which means our node structure is referenced in {` parser.tab.h}, but {` tree.h} isn't included there.
All in all, we'll have 4 source files for our simple front-end:
:unordered
-- [`lexer.l`]
+- {` lexer.l}
- ```lex
- 'include ./proper/lexer.l
+ 'def LANG lex
+ ```
+ 'snippet 1 $ ./proper/lexer.l
-- [`parser.y`]
+- {` parser.y}
- ```yacc
- 'include ./proper/parser.y
+ 'def LANG yacc
+ ```
+ 'snippet 1 $ ./proper/parser.y
-- [`tree.h`]
+- {` tree.h}
```c
- 'include ./proper/tree.h
+ 'snippet 1 $ ./proper/tree.h
-- [`tree.c`]
+- {` tree.c}
```c
- 'include ./proper/tree.c
+ 'snippet 1 $ ./proper/tree.c
We compile everything:
@@ -1095,20 +1126,20 @@ We compile everything:
```bash
flex lexer.l && bison -d parser.y && gcc lex.yy.c parser.tab.c tree.c
-Now, let's create the file [`test.txt`]:
+Now, let's create the file {` test.txt}:
```
-'include proper/test.txt
+'snippet 1 $ proper/test.txt
and run our front-end on it:
```bash
-./a.out test.txt
+\./a.out test.txt
Our output will be:
```
-'include proper/test_output.txt
+'snippet 1 $ proper/test_output.txt
Perfect, we have a good looking tree!
@@ -1118,4 +1149,6 @@ Originally I planned to put everything in one blog post, but writing the front-e
Additionally, while doing research, I found out the course actually skipped over a lot of important topics, which I'll first need to research.
Future parts will be linked right below the title at the very top, but it will probably be quite a while until I write them.
-Many thanks to [url https://github.com/dtagarev Dimitar Tagarev] for his help with reviewing this post.
+Many thanks to {url Dimitar Tagarev;https://github.com/dtagarev} for his help with reviewing this post.
+
+{footnotes}
diff --git a/src/blog/switchut-izgorq/index.du b/src/blog/switchut-izgorq/index.du
index 1f23862..b9e5ee3 100644
--- a/src/blog/switchut-izgorq/index.du
+++ b/src/blog/switchut-izgorq/index.du
@@ -1,9 +1,9 @@
-# Суичът изгоря!
+'def title Суичът изгоря!
+'def desc Как човек си изкарва безплатен суич заради слабите умения на мрежари
-'define expected-reading 2 min
-'define created 18 November 2024
-'define edited 18 November 2024
-[$pagenav]
+# {title}
+
+{pagenav 2 min;18 November 2024;18 November 2024}
Преди няколко месеца, интернетът у-нас спря.
Все още ползваме интернет "по медна свързаност", така че проблемът почти винаги се свежда до мрежовия шкаф на улицата, който всички компании оставят в безразбор.
@@ -11,22 +11,22 @@
Обаче, тъкмо като интернетът се върна и мрежарят беше готов да си тръгне, услугата взе че спря отново.
Вече доста изнервен, след като провери шкафът още един път, влезе в сградата, изтръгна старият суич (комутатор, но аз съм отраснал с английските наименования), замени го с нов и всичко тръгна.
-Неговият отговор, разбира се, беше че "Суичът е изгорял", заедно с един [*любезен*] коментар как "Тази инсталация вече е стара, трябва да си купите оптичен интернет, за да не ви горят суичовете и да не трябва да идвам аз!"
+Неговият отговор, разбира се, беше че "Суичът е изгорял", заедно с един {i любезен} коментар как "Тази инсталация вече е стара, трябва да си купите оптичен интернет, за да не ви горят суичовете и да не трябва да идвам аз!"
Предвидимо, самият суич ни го беше оставил и си тръгна по пътя.
-Та по-късно през деня седнах с един [url https://www.globalsources.com/AC-DC-adapter/plug-in-AC-DC-Adapter-1188075760p.htm стар AC/DC адаптер] и какво намирам: устройството си работи перфектно.
+Та по-късно през деня седнах с един {url стар AC/DC адаптер;https://www.globalsources.com/AC-DC-adapter/plug-in-AC-DC-Adapter-1188075760p.htm} и какво намирам: устройството си работи перфектно.
-[image ./img/switch-on.JPG "Разбира се, тествах и самите портове дали пускат данни"]
+{img "Разбира се, тествах и самите портове дали пускат данни";./img/switch-on.JPG}
Отдолу си има етикет на който пише, че приема 12V на 0.5A, единствено не пише дали центърът е положителен или отрицателен.
След малко бърникане с мултицедът, лесно се вижда че първото е вярно.
-[image ./img/switch-back.JPG "Хартиеното тиксо с полярността е моя добавка"]
+{img "Хартиеното тиксо с полярността е моя добавка";./img/switch-back.JPG}
-Благодарение на етикетът, бързо се намира и оригиналната [url https://networkpartner.eu/product/8-port-gb-switch/ уебстраница на която NetworkPartner са го продавали].
+Благодарение на етикетът, бързо се намира и оригиналната {url уебстраница на която NetworkPartner са го продавали;https://networkpartner.eu/product/8-port-gb-switch/}.
Единственият въпрос който остава, е какво е накарало интернетът да спре втория път?
-Оригиналната инсталация идва от М-Тел, и техния [*талант*] е решил да остави суичът да си виси във въздуха, държан само от кабелите, които се свързват към него, включително кабела за захранване.
+Оригиналната инсталация идва от М-Тел, и техния {i талант} е решил да остави суичът да си виси във въздуха, държан само от кабелите, които се свързват към него, включително кабела за захранване.
Моето предположение е, че захранването просто се е изплъзнало с малко от буксата докато са го оглеждали.
diff --git a/src/blog/taming-the-fun-too/index.du b/src/blog/taming-the-fun-too/index.du
index 07e7b63..018f6ae 100644
--- a/src/blog/taming-the-fun-too/index.du
+++ b/src/blog/taming-the-fun-too/index.du
@@ -1,55 +1,51 @@
-# Taming the Fun-too
+'def title Taming the Fun-too
+'def desc Stories of my troubles (and eventual triumph) with Funtoo
-'define expected-reading 7 min
-'define created 04 December 2022
-'define edited 04 December 2022
-[$pagenav]
+# {title}
-Let's set the scene: it's October of last year and I just began my first year as a university student. For the first time in my life, I was able to meet people who were significantly [~nerdier~] cooler than me.
-One particular dude I met introduced me to [url https://funtoo.org Funtoo], a boutique fork of [url https://gentoo.org Gentoo].
+{pagenav 7 min;04 December 2022;04 December 2022}
+
+Let's set the scene: it's October of last year and I just began my first year as a university student. For the first time in my life, I was able to meet people who were significantly {s nerdier} cooler than me.
+One particular dude I met introduced me to {url Funtoo;https://funtoo.org}, a boutique fork of {url Gentoo;https://gentoo.org}.
Now, I'm not a very big fan of distro hopping, it takes too much time and you often find yourself not liking the finished product, resulting in further distro hopping.
-However, at that time I was a bit softened by my growing pains with Fedora, the sweat promises of improved efficiency and usability, and the fact that fun is in the name! [*What could go wrong*] :)
+However, at that time I was a bit softened by my growing pains with Fedora, the sweat promises of improved efficiency and usability, and the fact that fun is in the name! {i What could go wrong} :)
-So, about a month later I bit the bullet, and installed it on my main computer. It has now been a tad more than a year later and I can comfortably say: [*a lot could go wrong...*]
+So, about a month later I bit the bullet, and installed it on my main computer. It has now been a tad more than a year later and I can comfortably say: {i a lot could go wrong...}
-\n
+<br/>
In the same way that a distro is made to solve a certain problem, every distro introduces a fundamental flaw in it's design. Ubuntu solves the "it's too complicated" problem, but introduces issues with performance. Arch solves "my packages are too old and what I need isn't there" issue, but introduces "my packages are too new and something just broke".
-'footnote ebuilds Files with instructions and settings for the package manager (portage) on how to build a specific package
-
-Then there's Funtoo. You might reason, since it's a fork of Gentoo, it's big flaw is the fact that you need to compile every package, with the prize being unparalleled efficiency. So did I, but as it turns out there is another, much larger flaw: [=packages=].
-The distribution is a lot smaller than it's big brother so a lot of stuff, understandably, cannot be tested. However, the real kicker is that package ebuilds[$ebuilds] are generated in a different way from Gentoo.
+Then there's Funtoo. You might reason, since it's a fork of Gentoo, it's big flaw is the fact that you need to compile every package, with the prize being unparalleled efficiency. So did I, but as it turns out there is another, much larger flaw: {b packages}.
+The distribution is a lot smaller than it's big brother so a lot of stuff, understandably, cannot be tested. However, the real kicker is that package ebuilds{fn Files with instructions and settings for the package manager (portage) on how to build a specific package} are generated in a different way from Gentoo.
This often means that using a Gentoo ebuild will make the problem even worse, but sometimes it does work out.
-\n
+<br/>
The first such problem child was QtWebEngine. As the name suggests, it gives the ability for graphical applications, made with the Qt framework, to render webpages.
-I don't [*need*] it for my setup, but there are a couple of useful programs that required it.
+I don't {i need} it for my setup, but there are a couple of useful programs that required it.
-What would happen is, after about 3 hours of compiling, the compilation would just stop, without any errors, anywhere. To add insult to injury, because I hadn't set up [url https://ccache.dev/ ccache] at the time, everything would have to be compiled [*all over again*].
+What would happen is, after about 3 hours of compiling, the compilation would just stop, without any errors, anywhere. To add insult to injury, because I hadn't set up {url ccache;https://ccache.dev/} at the time, everything would have to be compiled {i all over again}.
A fairly deep dive into different forums led me to the wondrous conclusion that I needed to remove a certain build flag, which wasn't enabled in the first place...
-After [*much*] tweaking and trying, I found out there just wasn't enough memory, the package needed at least 32 GiB (including swap) of memory for a successful compilation... D'oh!
-And here comes the really bad part: I had setup a swapfile of adequate size! However, as it turned out, in the configuration I tried loading it before loading the drive it was stored in... [=Double D'OH!!=]
+After {i much} tweaking and trying, I found out there just wasn't enough memory, the package needed at least 32 GiB (including swap) of memory for a successful compilation... D'oh!
+And here comes the really bad part: I had setup a swapfile of adequate size! However, as it turned out, in the configuration I tried loading it before loading the drive it was stored in... {b Double D'OH!!}
-\n
+<br/>
Then came the big boss: python. Now, I wasn't planning on doing any software development with it, but as it turned out, other people had, so certain packages had building issues.
And what was the exact issue you might ask?
-Well, to put it simply, Funtoo had official ebuilds for python 3.7, but a lot of packages needed at least version 3.8. This time however, I had a [*brilliant*] idea: I would copy Gentoo's python 3.8 ebuilds!
-
-'footnote circular-dependency To build package A you'll need to have package B installed. But to build package B, you'll need package A installed.
+Well, to put it simply, Funtoo had official ebuilds for python 3.7, but a lot of packages needed at least version 3.8. This time however, I had a {i brilliant} idea: I would copy Gentoo's python 3.8 ebuilds!
What I didn't realize, was that I had unknowingly opened Pandora's box.
-Over time I needed to install more and more python packages from Gentoo, until one day I created an [*unsolvable*] circular dependency[^circular-dependency].
-Usually there are solutions to such situations, but I kid you not, I had tried [=everything=] and [=nothing worked=].
+Over time I needed to install more and more python packages from Gentoo, until one day I created an {i unsolvable} circular dependency{fn To build package A you'll need to have package B installed. But to build package B, you'll need package A installed.}.
+Usually there are solutions to such situations, but I kid you not, I had tried {b everything} and {b nothing worked}.
This time, there isn't even a solution, I just made sure to never upgrade these packages again.
Which proved problematic, since these packages were important and over time other stuff broke, but that wouldn't be relevant for long.
-\n
+<br/>
Not too soon after, armageddon struck: glibc, GNU's C library. All I wanted to do was try out Ungoogled Chromium, but not as a flatpak.
The only thing standing in the way was the requirement of "glibc 3.4.29", while all I had was 2.70.0.
@@ -64,17 +60,17 @@ Aborting to save your system.
"Umm what?" was my reaction too. For reasons not completely clear to me, this turns out to be yet another roadblock. Did I mention a couple applications also stopped working after the upgrade?
Unfortunately my believes and ego were firmly set in stone, "Yeah, but I know what I'm doing, I'm downgrading from a non-Funtoo glibc, it will be fine!"
-A sanity check override and a package downgrade later, [*it wasn't...*]
+A sanity check override and a package downgrade later, {i it wasn't...}
Yes, my system was broken. Very broken. So broken in fact, portage wasn't working, so un-downgrading was not an option. And, of course, booting successfully my machine up ever again wasn't an option either...
-Thank goodness for [url https://github.com/linuxmint/timeshift Timeshift]'s system restore functionality or I would've had to rebuild my whole system.
+Thank goodness for {url Timeshift;https://github.com/linuxmint/timeshift}'s system restore functionality or I would've had to rebuild my whole system.
-\n
+<br/>
-There are [=a lot=] of other situations in which Funtoo's package difficulties and my sheer incompetence have led to wasted time and broken stuff, but these are the main ones that stand out in my mind (or more accurately, the ones that I still remember). Nowadays I use the distro in a much smarter fashion, with a much tighter grip.
+There are {b a lot} of other situations in which Funtoo's package difficulties and my sheer incompetence have led to wasted time and broken stuff, but these are the main ones that stand out in my mind (or more accurately, the ones that I still remember). Nowadays I use the distro in a much smarter fashion, with a much tighter grip.
-'footnote mask All ebuilds that are "masked", will not be used (therefore, corresponding package will not be compiled and installed/upgraded)
-
-Although I still need Gentoo packages, I install them from Funtoo's portage Gentoo kit.\n
-Although I still have issues with packages not being able to be built, I just mask[$mask] them until I have adequate time/energy (or until someone fixes it).\n
+Although I still need Gentoo packages, I install them from Funtoo's portage Gentoo kit.<br/>
+Although I still have issues with packages not being able to be built, I just mask{fn All ebuilds that are "masked", will not be used (therefore, corresponding package will not be compiled and installed/upgraded)} them until I have adequate time/energy (or until someone fixes it).<br/>
Although everything that has happened, for now, I'm still sticking with Funtoo.
+
+{footnotes}
diff --git a/src/blog/the-physics-behind-a-black-hole-shader/index.du b/src/blog/the-physics-behind-a-black-hole-shader/index.du
index 35c0450..fdb6589 100644
--- a/src/blog/the-physics-behind-a-black-hole-shader/index.du
+++ b/src/blog/the-physics-behind-a-black-hole-shader/index.du
@@ -1,27 +1,27 @@
-# The physics behind a black hole shader
+'def title The physics behind a black hole shader
+'def desc A deep dive into some of the physics (and mathematics) required for implementing a black hole shader
-'define expected-reading 22 min
-'define created 12 December 2023
-'define edited 06 October 2024
-[$pagenav]
+# {title}
+
+{pagenav 22 min;12 December 2023;06 October 2024}
:contents
:numbered
-1. [url #what-do-the-physics-say What do the physics say?]
+1. {uhref What do the physics say?}
.numbered
- 1. [url #what-is-gravity What is gravity?]
- 2. [url #what-does-it-mean-to-bend-space What does it mean to bend space?]
- 3. [url #how-to-handle-the-EFEs How to handle the EFEs?]
- 4. [url #what-is-a-black-hole What is a black hole?]
- 5. [url #what-about-speed-and-time What about speed and time?]
+ 1. {uhref What is gravity?}
+ 2. {uhref What does it mean to bend space?}
+ 3. {uhref How to handle the EFEs?}
+ 4. {uhref What is a black hole?}
+ 5. {uhref What about speed and time?}
-2. [url #finding-a-formula Finding a formula]
-3. [url #applying-the-formula-to-bend-lights-path Applying the formula to “bend” light’s path]
+2. {uhref Finding a formula}
+3. {uhref Applying the formula to “bend” light’s path}
.numbered
- 1. [url #properties-of-a-black-hole Properties of a black hole]
+ 1. {uhref Properties of a black hole}
-4. [url #light-bending-algorithm Light-bending algorithm]
-5. [url #appendix Appendix]
+4. {uhref Light-bending algorithm}
+5. {uhref Appendix}
@@ -30,9 +30,9 @@ I chose to create an interactive and animated black hole demo.
The primary idea was to show how the gravitational pull of black holes "bends" light and how the result looks from different points of view.
Then in the December of that same year, I sat down and started writing a blog post (as you may notice from the "Created" date), explaining how some of the more complicated parts were made.
-Funnily enough, I started finding errors... a [*lot*] of errors.
+Funnily enough, I started finding errors... a {i lot} of errors.
-As it turned out, my implementation was completely wrong, but somehow I fudged the formulas around in just the right way to make it [*look*] correct.
+As it turned out, my implementation was completely wrong, but somehow I fudged the formulas around in just the right way to make it {i look} correct.
So the post got delayed and sparsely rejuvenated over the following months.
For this reason I chose to take up two related electives this year: one on general relativity and one on ray tracing, with the hopes of gaining enough understanding of the material to rework the original solution into something proper.
@@ -47,13 +47,13 @@ I'll assume you don't know much about physics, but are familiar with mathematics
The "big words" version of what we're going to explore is:
-'define EFE https://en.wikipedia.org/wiki/Einstein_field_equations
+'def EFE https://en.wikipedia.org/wiki/Einstein_field_equations
-Using [url [$EFE] Einstein's field equations], we can precisely calculate the curvatures in space(time) at every point around a black hole.
-Obviously we're going to use [url https://en.wikipedia.org/wiki/Schwarzschild_metric Schwarzschild metric] on a (Schwarzschild) black hole.
-To further simplify our calculations, we can make approximations using [url https://en.wikipedia.org/wiki/Celestial_mechanics celestial mechanics].
+Using {url Einstein's field equations;{EFE}}, we can precisely calculate the curvatures in space(time) at every point around a black hole.
+Obviously we're going to use {url Schwarzschild metric;https://en.wikipedia.org/wiki/Schwarzschild_metric} on a (Schwarzschild) black hole.
+To further simplify our calculations, we can make approximations using {url celestial mechanics;https://en.wikipedia.org/wiki/Celestial_mechanics}.
-This is not [*necessary*] to understand, but it will make our goal [=much=] clearer.
+This is not {i necessary} to understand, but it will make our goal {b much} clearer.
Now, let's try and unravel everything.
@@ -62,70 +62,62 @@ Now, let's try and unravel everything.
Everything with mass applies a "pulling" force to everything else with mass.
It's easy to see this is true, but we get into trouble when trying to find a formula which predicts/calculates that force.
-Newton gave it a good shot, with his [url https://en.wikipedia.org/wiki/Newton%27s_laws_of_motion 3 laws of motion], which proved to be correct for about a century and a half.
+Newton gave it a good shot, with his {url 3 laws of motion;https://en.wikipedia.org/wiki/Newton%27s_laws_of_motion}, which proved to be correct for about a century and a half.
They even helped the discovery of Neptune, since measurements showed that the orbit of Uranus didn't meet expectations if there wasn't another planet meddling with things.
-The real crux of the issue came when the same problem occurred with [url https://en.wikipedia.org/wiki/Mercury_%28planet%29#Advance_of_perihelion Mercury's orbit], but no new planet was found.
+The real crux of the issue came when the same problem occurred with {url Mercury's orbit;https://en.wikipedia.org/wiki/Mercury_%28planet%29#Advance_of_perihelion}, but no new planet was found.
-As it turned out, Newton's formulae had only been approximations, they worked when light (and therefore [url https://www.youtube.com/watch?v=msVuCEs8Ydo causality, or the speed at which changes propagate]) had infinite speed.
+As it turned out, Newton's formulae had only been approximations, they worked when light (and therefore {url causality, or the speed at which changes propagate;https://www.youtube.com/watch?v=msVuCEs8Ydo}) had infinite speed.
-Albert Einstein's general theory of relativity showed that gravity wasn't a "force which pulled", it was actually an effect which [=bent=] space.
-And that only happened because the ([=constant=]) speed of light wasn't infinite.
+Albert Einstein's general theory of relativity showed that gravity wasn't a "force which pulled", it was actually an effect which {b bent} space.
+And that only happened because the ({b constant}) speed of light wasn't infinite.
### What does it mean to bend space?
-'footnote line-definition This is the mathematical definition of a line, obviously in conversation we refer to a line segment as a line. But this distinction will be useful.
-
Think of a flat surface, like a table.
What is the shortest distance between two points?
Obviously, that's a straight line segment.
-If you then extend that segment, so it has an infinite length, it becomes a line[$line-definition].
+If you then extend that segment, so it has an infinite length, it becomes a line{fn This is the mathematical definition of a line, obviously in conversation we refer to a line segment as a line. But this distinction will be useful.}.
However, what if our surface isn't flat?
Imagine two points on a sphere, what is the shortest distance between them?
-Obviously, it's an arc of a circle and extending it to it's maximum possible length, we get a [url https://en.wikipedia.org/wiki/Great_circle great circle].
+Obviously, it's an arc of a circle and extending it to it's maximum possible length, we get a {url great circle;https://en.wikipedia.org/wiki/Great_circle}.
-[image ./img/Illustration_of_great-circle_distance.svg.png]\n
-[*Image by CheCheDaWaff on [url https://commons.wikimedia.org/w/index.php?curid=48187293 Wikipedia]*]
+{img ./img/Illustration_of_great-circle_distance.svg.png}<br/>
+{i Image by CheCheDaWaff on {url Wikipedia;https://commons.wikimedia.org/w/index.php?curid=48187293}}
Now, what does it mean to go "forwards"?
On a flat surface, we can define it as "following a (straight) line segment", on our sphere we can say "following an arc of a great circle".
-'footnote geodesics-are-local This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purposes. More info can be found on [url https://en.wikipedia.org/wiki/Geodesic#Introduction Wikipedia].
-
-Better yet, in geometry there are [url https://en.wikipedia.org/wiki/Geodesic geodesics], the general term for a curve on any surface which is the shortest[$geodesics-are-local] path between any two points.
+Better yet, in geometry there are {url geodesics;https://en.wikipedia.org/wiki/Geodesic}, the general term for a curve on any surface which is the shortest{fn This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purposes. More info can be found on {url Wikipedia;https://en.wikipedia.org/wiki/Geodesic#Introduction}.} path between any two points.
So now we can say "going forwards means going along a geodesic".
-'footnote parallels-of-latitude You might think about the latitudinal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest.
-
It's important to note that an arbitrary geodesic doesn't have most properties you might be used to.
-For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect[$parallels-of-latitude].
+For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect{fn You might think about the latitudinal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest.}.
-This is what gravity does, it doesn't pull or push, it [*bends*], and more precisely, it [=bends geodesics=].
-Furthermore, we live in three spacial dimensions, so we can move in three [*different directions*].
+This is what gravity does, it doesn't pull or push, it {i bends}, and more precisely, it {b bends geodesics}.
+Furthermore, we live in three spacial dimensions, so we can move in three {i different directions}.
The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship.
-Although not yet mentioned, you need to know that [=photons=] (light) [=don't have mass=]!
+Although not yet mentioned, you need to know that {b photons} (light) {b don't have mass}!
In effect, in a universe where there is only light bouncing around, Newton's equations still work.
-On that note, the point that light [=doesn't=] travel at an infinite speed is significant.
+On that note, the point that light {b doesn't} travel at an infinite speed is significant.
When the opposite is true, General Theory of Relativity collapses into the Newtonian equations!
-Going back on track, Einstein gives us the necessary equations for those geodesics, the [url [$EFE] Einstein Field Equations].
+Going back on track, Einstein gives us the necessary equations for those geodesics, the {url Einstein Field Equations;{EFE}}.
### How to handle the EFEs?
Although they're called equations the result/output we get from solving them isn't a number!
-It's a function, which [*more or less*] takes the parameters of objects in the universe and returns [*how*] they will all behave.
-To be more precise, the output isn't [*really*] a function, it's a "metric", which is a distinctly different mathematical object.
-
-'footnote schwm-assumptions He also assumed the body didn't have an electric charge and the [url https://en.wikipedia.org/wiki/Cosmological_constant cosmological constant] is zero.
+It's a function, which {i more or less} takes the parameters of objects in the universe and returns {i how} they will all behave.
+To be more precise, the output isn't {i really} a function, it's a "metric", which is a distinctly different mathematical object.
-In the 1910s Schwarzschild solved the equations for a universe where there is only one non-rotating[$schwm-assumptions] particle with mass, then in the 1960s the equations were solved when that particle could rotate, that's it.
+In the 1910s Schwarzschild solved the equations for a universe where there is only one non-rotating{fn He also assumed the body didn't have an electric charge and the {url cosmological constant;https://en.wikipedia.org/wiki/Cosmological_constant} is zero.} particle with mass, then in the 1960s the equations were solved when that particle could rotate, that's it.
There are plenty of other mathematical solutions, but we have been able to relate the "real" world to only those two.
This may sound unsatisfactory, but in practice, it's quite enough.
-In the solar system, [url https://en.wikipedia.org/wiki/Solar_System >99.86% of mass is in the Sun], so assuming all other objects are massless, we get enough precision to explain Mercury's orbit.
+In the solar system, {url >99.86% of mass is in the Sun;https://en.wikipedia.org/wiki/Solar_System}, so assuming all other objects are massless, we get enough precision to explain Mercury's orbit.
We can apply the same idea to our simulation, leaving all objects which aren't our black hole without mass.
Schwarzschild's metric and accompanying black hole properties are the simplest possible solution, so we'll use that.
@@ -134,8 +126,8 @@ Schwarzschild's metric and accompanying black hole properties are the simplest p
Let's imagine atoms as a set of glass marbles, scattered on a table:
-[image https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg]\n
-[*Image from By Okkisafire on [url https://commons.wikimedia.org/w/index.php?curid=30338734 Wikipedia]*]
+{img https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg}<br/>
+{i Image from By Okkisafire on {url Wikipedia;https://commons.wikimedia.org/w/index.php?curid=30338734}}
Now, start pushing from all sides of the table to it's center.
In the beginning, you'll mostly roll them, until they all get in contact with each other.
@@ -145,37 +137,35 @@ By increasing the force with which you push on them, after a certain threshold,
Those shards will still have some fight in them, so after increasing your force by another level, you'll turn all of those shards into tiny glass granules.
A similar occurrence happens with atoms.
-Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbiting electrons) all nuclei will be "touching" and the [url https://en.wikipedia.org/wiki/Nuclear_force nuclear force] will keep them together.
+Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbiting electrons) all nuclei will be "touching" and the {url nuclear force;https://en.wikipedia.org/wiki/Nuclear_force} will keep them together.
By further increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles.
-'footnote matter-together Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand.
-
-Assuming an enormous explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[$matter-together].
-However, those subatomic particles are more commonly referred to as [url https://en.wikipedia.org/wiki/Elementary_particle elementary particles], meaning there are no "granules" into which the elementary particles can break down.
+Assuming an enormous explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"{fn Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand.}.
+However, those subatomic particles are more commonly referred to as {url elementary particles;https://en.wikipedia.org/wiki/Elementary_particle}, meaning there are no "granules" into which the elementary particles can break down.
It's not possible for those particle to be completely unbreakable, since that would mean they could theoretically sustain infinite amounts of force.
Such an assumption is unthinkable.
Then that leaves us with only one solution: laws of matter "break".
If nothing can keep the elementary particles "together", so keep matter "together", then the result is a sort of "collapse", all of that matter just "deflates" into a single, infinitely small point (but the amount of mass isn't infinite, it's the sum of mass from the particles that collapsed).
-That point is called a [=black hole=].
+That point is called a {b black hole}.
This object is very bizarre, generally it doesn't have too much properties, but the ones it has are really unique.
In our case, the only important part is it's effect on gravity, and more precisely, light.
-Since a black hole is a single infinitely small point, then all of it's mass is concentrated on that point, making it alter the geodesics in a relatively small area of space [=a lot=].
+Since a black hole is a single infinitely small point, then all of it's mass is concentrated on that point, making it alter the geodesics in a relatively small area of space {b a lot}.
So much so, if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitesimal point:
-[image https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/CNX_UPhysics_13_07_spacetime.png/800px-CNX_UPhysics_13_07_spacetime.png?20171124170318]\n
-[*The white lines are our geodesics*]\n
-[*Image by OpenStax University Physics on [url https://commons.wikimedia.org/w/index.php?curid=64307901 Wikipedia]*]
+{img https://upload.wikimedia.org/wikipedia/commons/9/91/CNX_UPhysics_13_07_spacetime.png?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original}<br/>
+{i The white lines are our geodesics}<br/>
+{i Image by OpenStax University Physics on {url Wikipedia;https://commons.wikimedia.org/w/index.php?curid=64307901}}
A fascinating realization is that light always travels along geodesics ("forwards"), therefore this extreme bending allows us to view otherwise obstructed objects.
-We call that effect [url https://en.wikipedia.org/wiki/Gravitational_lens gravitational lensing].
+We call that effect {url gravitational lensing;https://en.wikipedia.org/wiki/Gravitational_lens}.
Though not unique to black holes, that's when the effect is strongest:
-[image https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg]\n
-[*Notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole*]
+{img https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg}<br/>
+{i Notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole}
I'll abstain from explaining the specifics of light, but you may think of it as a small particle, "similar" to an electron, travelling through space.
In fact, Newton understood light to be just that, and called the underlying particle a "corpuscle".
@@ -187,29 +177,29 @@ Two of the most significant things Einstein's theory shows, which I've left out
Which also signifies that our geodesics are actually four dimensional, or in other words, gravity also bends the observed passage of time!
This is relevant for light, since it's speed is constant and it always travels along a geodesic, but to an outside observer it doesn't look that way.
-However, in our simulation, we [=only=] care about how thing look, so it will make our live much simpler if we try to ignore reality wherever we can.
+However, in our simulation, we {b only} care about how thing look, so it will make our live much simpler if we try to ignore reality wherever we can.
Therefore, to calculate by how much light will move and change, we'll start with the EFEs and then simplify and approximate until we get something useable.
## Finding a formula
-Let's get down to business, our starting point, the [url https://en.wikipedia.org/wiki/Schwarzschild_metric Schwarzschild metric], in Schwarzschild coordinates, looks like this:
+Let's get down to business, our starting point, the {url Schwarzschild metric;https://en.wikipedia.org/wiki/Schwarzschild_metric}, in Schwarzschild coordinates, looks like this:
-[image ./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png]
+{img ./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png}
-[=YOUCH!=]
+{b YOUCH!}
-The variables themselves aren't that bad: [`c`] is the speed of light, <code>&tau;</code> is time, <code>&Omega;</code>, [`t`] and [`r`] are Schwarzschild coordinates.
+The variables themselves aren't that bad: {` c} is the speed of light, <code>&tau;</code> is time, <code>&Omega;</code>, {` t} and {` r} are Schwarzschild coordinates.
-However, as you can see, there are two big problems: we have to calculate derivatives (that's what the [`d`] signifies) and convert from Schwarzschild coordinates to normal (euclidean) coordinates, that the computer understands "natively".
-This would be [=too slow=] to render in real time.
+However, as you can see, there are two big problems: we have to calculate derivatives (that's what the {` d} signifies) and convert from Schwarzschild coordinates to normal (euclidean) coordinates, that the computer understands "natively".
+This would be {b too slow} to render in real time.
-Thankfully [url https://github.com/rantonels Riccardo Antonelli] was able to do all of our coordinate conversions and use Newton's ideas to simplify the living crap out of that monster, turning it into something digestible:
+Thankfully {url Riccardo Antonelli;https://github.com/rantonels} was able to do all of our coordinate conversions and use Newton's ideas to simplify the living crap out of that monster, turning it into something digestible:
-[image ./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png]
+{img ./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png}
Explaining his steps and the formula is way beyond the scope of my understanding and this post.
-He explains it in more mathematical detail [url http://spiro.fisica.unipd.it/~antonell/schwarzschild/ here].
+He explains it in more mathematical detail {url here;http://spiro.fisica.unipd.it/~antonell/schwarzschild/}.
But now, finally, we can get a plan for our simulation:
@@ -219,7 +209,7 @@ But now, finally, we can get a plan for our simulation:
- rinse and repeat until the light hits something
Question now is: what do all of those letters represent?
-This turned out to be a much harder problem than it should have, I actually had to refer [url https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py Ricardo Antonelli's] and [url https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes Dmitry Brant's] implementation in their projects, alongside copious articles on Wikipedia to fully grasp how to put it to work.
+This turned out to be a much harder problem than it should have, I actually had to refer {url Ricardo Antonelli's;https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py} and {url Dmitry Brant's;https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes} implementation in their projects, alongside copious articles on Wikipedia to fully grasp how to put it to work.
## Applying the formula to "bend" light's path
@@ -227,20 +217,20 @@ The direction, alongside the amount by which the particle moves, can be represen
Referring to the formula again:
-[image ./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png]
+{img ./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png}
-[`F[^&rarr;^]`] returns a force vector ([`F`] for "force" and [`[^&rarr;^]`] for "vector"): any force acting on an object has a strength (magnitude) and a direction.
+{` F{^ &rarr\;}} returns a force vector ({` F} for "force" and {` {^ &rarr\;}} for "vector"): any force acting on an object has a strength (magnitude) and a direction.
Imagine you are pushing a box: you are applying some force to it in a "forward" direction.
If you pull the box, you'll apply some force in a "backward" direction.
This force vector conveys how much and in what direction exactly the black hole is "pulling" on the corpuscle.
-Although the function takes in only one argument, [`r`], that doesn't mean that [`h`] or [`r[^^^]`] aren't also arguments:
+Although the function takes in only one argument, {` r}, that doesn't mean that {` h} or {` r{^ ^}} aren't also arguments:
:unordered
-- [`r`] is the distance from the center of the black hole (the singularity) to the [=current=] position of the corpuscle.
+- {` r} is the distance from the center of the black hole (the singularity) to the {b current} position of the corpuscle.
-- [`h`] is the magnitude of the [url https://en.wikipedia.org/wiki/Specific_angular_momentum "specific angular momentum"] of the light "particle".
+- {` h} is the magnitude of the {url "specific angular momentum";https://en.wikipedia.org/wiki/Specific_angular_momentum} of the light "particle".
.p
"Normal" linear momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of an object in linear motion (that's why it's in kg\*m/s).
@@ -248,14 +238,12 @@ Although the function takes in only one argument, [`r`], that doesn't mean that
How do you forcefully stop it?
.p
- You can put a [*really*] heavy barrier on the tracks, in front of the train.
+ You can put a {i really} heavy barrier on the tracks, in front of the train.
Since the train is moving at a really great speed, this barrier will have to be much much heavier (with much more mass) than the train itself.
- 'footnote hitting-trains Of course, I'm assuming the trains are strong enough they won't break upon the collision.
-
.p
Alternatively, you can "launch" something against the train, meaning you can put a second train, moving in the opposite direction of the first train, so they hit head-on.
- Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, upon collision they would both stop[$hitting-trains].
+ Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, upon collision they would both stop{fn Of course, I'm assuming the trains are strong enough they won't break upon the collision.}.
If the second travels at twice the speed, then it can have half of the mass of the first to produce the same effect.
.p
@@ -268,41 +256,38 @@ Although the function takes in only one argument, [`r`], that doesn't mean that
.p
The specific angular momentum is the angular momentum of an object, divided by it's mass.
It's magnitude kind of tells us which property is more prevalent in the momentum, the mass or the speed.
- For the same angular momentum, a long (big magnitude) [*specific*] angular momentum means our object is small and moves fast, while for a short (small magnitude) [*specific*] angular momentum out object is large and moves slowly.
-
- 'footnote angular-momentum Angular momentum is actually [url https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition defined using the cross product]
- 'footnote light-has-no-mass As mentioned, light has no mass, so this version of the formula wouldn't work.
+ For the same angular momentum, a long (big magnitude) {i specific} angular momentum means our object is small and moves fast, while for a short (small magnitude) {i specific} angular momentum out object is large and moves slowly.
.p
- Another simplification we need to is [=make our black hole stationary=]!
- Then, rather than finding the angular momentum[$angular-momentum] and dividing by the mass[$light-has-no-mass], we'll use another formula:
+ Another simplification we need to is {b make our black hole stationary}!
+ Then, rather than finding the angular momentum{fn Angular momentum is actually {url defined using the cross product;https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition}} and dividing by the mass{fn As mentioned, light has no mass, so this version of the formula wouldn't work.}, we'll use another formula:
- .p [image ./img/specific-angular-momentum-wikipedia.png]
+ .p {img ./img/specific-angular-momentum-wikipedia.png}
.p
- where [=in this specific formula only=] [`r`] is the vector from the singularity to the corpuscle and [`v`] is light's velocity.
+ where {b in this specific formula only} {` r} is the vector from the singularity to the corpuscle and {` v} is light's velocity.
.p
The cross product returns a vector, so we'll need to take the magnitude of the result and plug that into the formula.
- It's also important that [=we calculate it only once, in the beginning=].
+ It's also important that {b we calculate it only once, in the beginning}.
So, we shouldn't be calculating the magnitude of the specific angular momentum every time the light "particle" is moved, rather we calculate it once, after it gets close enough to be affected by the black hole.
.p
You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it.
You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple.
-- [`r[^&#94;^]`] is the normalized ([url https://en.wikipedia.org/wiki/Unit_vector unit], hence the [`^`] on top) vector from the center of the black hole to the light particle:
+- {` r{^ &#94;}} is the normalized ({url unit;https://en.wikipedia.org/wiki/Unit_vector}, hence the {` ^} on top) vector from the center of the black hole to the light particle:
- .p [image ./img/normalize-vector-wikipedia.png]
+ .p {img ./img/normalize-vector-wikipedia.png}
Finally, putting all needed variables together in one proper function, we get:
-[image ./img/variables-expanded.png Refer to "Antonelli’s formula - explained" in the Appendix]
+{img Refer to "Antonelli’s formula - explained" in the Appendix;./img/variables-expanded.png}
-As you may notice, this can be simplified, if we substitute [`r[^&#94;^]`]:
+As you may notice, this can be simplified, if we substitute {` r{^ &#94;}}:
-[image ./img/antonelli-formula-expanded.png Refer to "Antonelli’s formula - simplified" in the Appendix]
+{img Refer to "Antonelli’s formula - simplified" in the Appendix;./img/antonelli-formula-expanded.png}
In effect, we pass the distance from the black hole to the corpuscle and the function returns how light's velocity changes.
@@ -312,39 +297,35 @@ For that we'll need to get even more familiar with black holes.
### Properties of a black hole
-'footnote no-hair-theorem The [url https://en.wikipedia.org/wiki/No-hair_theorem no-hair theorem] states that stationary black holes are characterized by only their mass, angular momentum and electric charge. By definition of a Schwarzschild black hole, the last two are null.
-
To summarize, we're working with a stationary Schwarzschild black hole.
-Meaning our black hole has only one property: mass[$no-hair-theorem].
+Meaning our black hole has only one property: mass{fn The {url no-hair theorem;https://en.wikipedia.org/wiki/No-hair_theorem} states that stationary black holes are characterized by only their mass, angular momentum and electric charge. By definition of a Schwarzschild black hole, the last two are null.}.
Everything else can be derived from it.
-There are three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [url https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit ISCO].
+There are three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and {url ISCO;https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit}.
The event horizon, also called the Schwarzschild radius, is the distance from the singularity, which once passed, nothing can return and escape.
The formula for it is:
-[image ./img/Schwarzschild-radius-wikipedia.png r_s = (2GM)/(c^2)]
+{img r_s = (2GM)/(c^2);./img/Schwarzschild-radius-wikipedia.png}
-where [`G`] is the [url https://en.wikipedia.org/wiki/Gravitational_constant gravitational constant] and [`M`] is the mass of the black hole (in kg).
+where {` G} is the {url gravitational constant;https://en.wikipedia.org/wiki/Gravitational_constant} and {` M} is the mass of the black hole (in kg).
The photon sphere is the distance from the singularity, in which photons start orbiting the black hole (and can either escape or pass the event horizon).
Formula:
-[image ./img/photon-sphere-wikipedia.png r = r_s * 3/2]
+{img r = r_s * 3/2;./img/photon-sphere-wikipedia.png}
-where [`G`] and [`M`] are the same as before, [`c`] is the speed of light in vacuum and [`r[^s^]`] is the aforementioned Schwarzschild radius.
-
-'footnote isco It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results.
+where {` G} and {` M} are the same as before, {` c} is the speed of light in vacuum and {` r{^ s}} is the aforementioned Schwarzschild radius.
Finally, the innermost stable circular orbit (ISCO), formally it's the distance, before which you can orbit the black hole, but once passed, you'll get sucked in and either get shot out or be forever lost past the event horizon.
-For our purposes, it's fine to approximate it as the maximum radius after which space-time isn't bent[$isco] and objects aren't affected.
+For our purposes, it's fine to approximate it as the maximum radius after which space-time isn't bent{fn It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results.} and objects aren't affected.
Formula:
-[image ./img/isco-wikipedia.png]
+{img ./img/isco-wikipedia.png}
Putting them all together, we should expect light to travel like this:
-[image https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif]
-[*Animation by Hugo Spinelli on [url https://commons.wikimedia.org/w/index.php?curid=138168679 Wikipedia]*]
+{img https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif}
+{i Animation by Hugo Spinelli on {url Wikipedia;https://commons.wikimedia.org/w/index.php?curid=138168679}}
## Light-bending algorithm
@@ -366,13 +347,13 @@ The simplest way to "track" this is just to limit how many times we can move the
An algorithm doing this would look a bit like this (in pseudocode, inspired by Python):
-[image ./img/algorithm.png Refer to "Algorithm" section of the Appendix]
+{img Refer to "Algorithm" section of the Appendix;./img/algorithm.png}
-as a reminder, here is the definition of [`F[^&rarr;^]`]:
+as a reminder, here is the definition of {` F{^ &rarr;}}:
-[image ./img/antonelli-formula-expanded.png]
+{img ./img/antonelli-formula-expanded.png}
-\n
+<br/>
That's it!
We have all of our theoretical background, formulae and algorithm to start work on our actual program.
@@ -383,19 +364,21 @@ To Be Continued!
### LaTeX source for equations
-The images for my custom LaTeX equations were created on [url https://latexeditor.lagrida.com/ latexeditor.lagrida.com], by using Firefox's built-in ability to screenshot HTML nodes, in particular the [url https://www.mathjax.org/ MathJax] node with the equation.
+The images for my custom LaTeX equations were created on {url latexeditor.lagrida.com;https://latexeditor.lagrida.com/}, by using Firefox's built-in ability to screenshot HTML nodes, in particular the {url MathJax;https://www.mathjax.org/} node with the equation.
#### Antonelli's formula - explained
-```latex
-'include ./antonelli_formula.tex
+```tex
+'snippet 1 $ ./antonelli_formula.tex
#### Antonelli's formula - simplified
-```latex
-'include ./antonelli_formula_simplified.tex
+```tex
+'snippet 1 $ ./antonelli_formula_simplified.tex
#### Algorithm
-```latex
-'include ./algorithm.tex
+```tex
+'snippet 1 $ ./algorithm.tex
+
+{footnotes}
diff --git a/src/blog/thinkpad-x270-my-favorite-machine/index.du b/src/blog/thinkpad-x270-my-favorite-machine/index.du
index f52d54d..6aad001 100644
--- a/src/blog/thinkpad-x270-my-favorite-machine/index.du
+++ b/src/blog/thinkpad-x270-my-favorite-machine/index.du
@@ -1,41 +1,41 @@
-# ThinkPad X270 - my favorite machine
+'def title ThinkPad X270 - my favorite machine
+'def desc Review of the laptop
-'define expected-reading 17 min
-'define created 30 August 2023
-'define edited 30 August 2023
-[$pagenav]
+# {title}
+
+{pagenav 17 min;30 August 2023;30 August 2023}
:contents
:numbered
-1. [url #context Context]
-2. [url #what-i-think What I Think]
+1. {uhref Context}
+2. {uhref What I Think}
.numbered
- 1. [url #display Display]
- 2. [url #cpu-and-ram CPU and RAM]
- 3. [url #hardware-support-and-chassis Hardware support and chassis]
- 4. [url #ports Ports]
- 5. [url #batteries Batteries]
- 6. [url #keyboard-and-power-button Keyboard and power button]
- 7. [url #trackpoint-and-mouse-pad Trackpoint and mouse pad]
- 8. [url #repairability Repairability]
- 9. [url #cooling Cooling]
- 10. [url #pricing Pricing]
+ 1. {uhref Display}
+ 2. {uhref CPU and RAM}
+ 3. {uhref Hardware support and chassis}
+ 4. {uhref Ports}
+ 5. {uhref Batteries}
+ 6. {uhref Keyboard and power button}
+ 7. {uhref Trackpoint and mouse pad}
+ 8. {uhref Repairability}
+ 9. {uhref Cooling}
+ 9. {uhref Pricing}
-3. [url #conclusion Conclusion]
+3. {uhref Conclusion}
ThinkPad laptops are generally well liked, a lot of people I know use them and every one that I've touched has been a pleasure to work with.
-Suffice to say, I've wanted to get one for quite a while now, so back in the middle of May I bit the bullet and spontaneously bought a second hand [url https://www.thinkwiki.org/wiki/X270_Detailed_Hardware_Information Thinkpad X270].
+Suffice to say, I've wanted to get one for quite a while now, so back in the middle of May I bit the bullet and spontaneously bought a second hand {url Thinkpad X270;https://www.thinkwiki.org/wiki/X270_Detailed_Hardware_Information}.
I've used it for the past 3 months, and in all honesty, it's not without it's drawback, but the X270 has easily become my favorite computer.
-[*Note: this whole review was written on the aforementioned Thinkpad X270, without external devices (like keyboard or monitor) attached.*]
+{i Note: this whole review was written on the aforementioned Thinkpad X270, without external devices (like keyboard or monitor) attached.}
## Context
-My main computer is a pre built (without only major upgrades) desktop tower with an [url https://www.intel.com/content/www/us/en/products/sku/77488/intel-core-i34160-processor-3m-cache-3-60-ghz/specifications.html i3-4160], scoring [url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317 3510 on CPU mark], paired with 16 gigs (for the past 9 months, otherwise I had 8 GB) of 1600 MHz memory, and a 1080p IPS monitor.
-I also own a laptop, the [url https://www.lenovo.com/gb/en/p/laptops/yoga/yoga-slim-series/yoga-s730/88ygs701077 Lenovo Yoga S730] with an [url https://ark.intel.com/content/www/us/en/ark/products/149091/intel-core-i78565u-processor-8m-cache-up-to-4-60-ghz.html i7-8565U], scoring [url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-8565U+%40+1.80GHz&id=3308 6152], 16 GB of 2133 MHz RAM and 1080p IPS monitor.
+My main computer is a pre built (without only major upgrades) desktop tower with an {url i3-4160;https://www.intel.com/content/www/us/en/products/sku/77488/intel-core-i34160-processor-3m-cache-3-60-ghz/specifications.html}, scoring {url 3510 on CPU mark;https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317}, paired with 16 gigs (for the past 9 months, otherwise I had 8 GB) of 1600 MHz memory, and a 1080p IPS monitor.
+I also own a laptop, the {url Lenovo Yoga S730;https://www.lenovo.com/gb/en/p/laptops/yoga/yoga-slim-series/yoga-s730/88ygs701077} with an {url i7-8565U;https://ark.intel.com/content/www/us/en/ark/products/149091/intel-core-i78565u-processor-8m-cache-up-to-4-60-ghz.html}, scoring {url 6152;https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-8565U+%40+1.80GHz&id=3308}, 16 GB of 2133 MHz RAM and 1080p IPS monitor.
Understanding my relationship with those machines is relevant to how I view the X270.
I got the desktop tower in 2015, and even at the time, it's specs were in the middle range.
@@ -44,21 +44,21 @@ Anyway, in all honesty, the only time when I wish for more power is in video gam
Summarising, 99% of the time it's hardware is more than sufficient.
The Yoga S730 was an "investment" into my future, since at the time I was going to programming lessons (which gave me a lot of the skills I have today) with my dad's laptop.
-With this new machine I could go to the lectures and write code freely on a [=very=] fast (considering I was doing C# programming in Visual Studio on Windows 10, speed was always needed) and physically light machine, without being slowed down by the cheap, 4 years old, 16 inch behemoth.
-From this point on, I was hooked on the 13 inch size, which as we all know is [url https://youtu.be/Za_Ul08dtj8?t=1208 the perfect size] and [url https://youtu.be/Q0h8wWlBxY0?t=1672 they should even make laptops that are any bigger].
+With this new machine I could go to the lectures and write code freely on a {b very} fast (considering I was doing C# programming in Visual Studio on Windows 10, speed was always needed) and physically light machine, without being slowed down by the cheap, 4 years old, 16 inch behemoth.
+From this point on, I was hooked on the 13 inch size, which as we all know is {url the perfect size;https://youtu.be/Za_Ul08dtj8?t=1208} and {url they should even make laptops that are any bigger;https://youtu.be/Q0h8wWlBxY0?t=1672}.
However, very quickly I found the ultrabook fashion of only including USB-C ports, very annoying to deal with, especially if you don't pay for an all-in-one dongle (which I didn't do for years).
-Additionally, the screen had [*no*] anti-gloss coating, so most of the time I was looking at my own reflection, rather than the actual screen contents.
+Additionally, the screen had {i no} anti-gloss coating, so most of the time I was looking at my own reflection, rather than the actual screen contents.
Final thought, in the beginning battery life wasn't that much of a problem, but nowadays the battery barely holds for 3-4 hours, and I think a cell inside is failing.
## What I Think
-My dream laptop was a "fat" Yoga S730 - 13 inches diagonally (an absolute [=MUST=]) with USB type A ports, a non-glossy display and better battery life.
+My dream laptop was a "fat" Yoga S730 - 13 inches diagonally (an absolute {b MUST}) with USB type A ports, a non-glossy display and better battery life.
Let's now consider the Thinkpad in question:
.bulleted
- 13 inches in size diagonally,
-- [*two*] USB type A ports and more
+- {i two} USB type A ports and more
- display with an anti-gloss coating
- both an external and internal battery (we'll talk about them later), allegedly being able to last 6-8 hours
@@ -66,17 +66,18 @@ Absolutely perfect... well, almost.
### Display
-By default, the laptop comes with a [=horrible=] 720p TFT display, with [=horrid=] color contrast, brightness and viewing angles.
-Surprisingly enough, online there were 1080p IPS drop-in replacements, and they weren't too expensive: the [url https://www.amazon.de/dp/B07RZQ5LPW/ref=pe_27091401_487024491_TE_item one I got from amazon.de cost me 115 euro] (including the 25 euro international shipping).
+By default, the laptop comes with a {b horrible} 720p TFT display, with {b horrid} color contrast, brightness and viewing angles.
+Surprisingly enough, online there were 1080p IPS drop-in replacements, and they weren't too expensive: the {url one I got from amazon.de cost me 115 euro;https://www.amazon.de/dp/B07RZQ5LPW/ref=pe_27091401_487024491_TE_item} (including the 25 euro international shipping).
The laptop itself did cost me ~170 euro, so the screen itself was 2/3 of the laptop price, but at 285 euro total, the deal was still a steal, at least considering where I live at.
-[url https://www.youtube.com/watch?v=hzI3U3up5xY Replacing the display itself was dead easy]: pop-open the bezel, disconnect the old, reconnect the new, put the bezel back on, boom!
+{url Replacing the display itself was dead easy;https://www.youtube.com/watch?v=hzI3U3up5xY}: pop-open the bezel, disconnect the old, reconnect the new, put the bezel back on, boom!
The only negative is that, since it's 1080p, my battery life decreased by 30-60 minutes.
Oddly enough though, if I set the refresh rate at 58.86 (or something else that's lower than 60.00, but this is the lowest I was able to go) the display seemed to use less power and I got that battery life back.
Here are the exact Linux commands I used (make sure you don't have any external displays connected):
```bash
+'emplace
# find your display name, mine was eDP-1; I got this from StackExchange somewhere I think
displayname="$(xrandr | grep connected | grep -v disconnected | cut -f 1 -d ' ')"
# get the exact needed display parameters for 1920x1080 resolution at 58.90 hertz refresh rate
@@ -87,24 +88,25 @@ modename=$(echo $displayparams | cut -f 1 -d ' ')
xrandr --newmode $displayparams
xrandr --addmode $displayname $modename
xrandr --output $displayname --mode $modename
+'endemplace
From now on, my opinion will refer to the X270 with the upgraded display.
### CPU and RAM
-The processor is underwhelming to say the least, my machine came with the [url https://www.intel.com/content/www/us/en/products/sku/88190/intel-core-i56300u-processor-3m-cache-up-to-3-00-ghz/specifications.html Intel Core i5-6300U], which has two cores at a base frequency of 2.50 GHz.
-It's [url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-6300U+%40+2.40GHz&id=2609 CPU Mark is about 3240], but if you were following, it scores a little bit worse than the [url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317 CPU on my desktop], so I'm used to it.
+The processor is underwhelming to say the least, my machine came with the {url Intel Core i5-6300U;https://www.intel.com/content/www/us/en/products/sku/88190/intel-core-i56300u-processor-3m-cache-up-to-3-00-ghz/specifications.html}, which has two cores at a base frequency of 2.50 GHz.
+It's {url CPU Mark is about 3240;https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-6300U+%40+2.40GHz&id=2609}, but if you were following, it scores a little bit worse than the {url CPU on my desktop;https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317}, so I'm used to it.
But I can understand that being a deal breaker for a lot of people.
The RAM wasn't too bad actually, I got 16 GB of DDR4 memory at 2133 MHz.
My desktop runs 16 GB of DDR3 memory at 1600 MHz, so in practice, even though the CPU is slightly slower, the overall machine always performs noticeably better than my desktop.
I must mention, on some devices there seems to be an issue, where the RAM module would very slightly move in it's slot when the laptop is held in a certain way, which will cause the computer to freeze.
-[url https://old.reddit.com/r/thinkpad/comments/jq53yt/freezing_x270x260x250_official_fix_a_bit_lmao/ The solution is to put something beneath it, as a standoff], but I haven't had to do this yet.
+{url The solution is to put something beneath it, as a standoff;https://old.reddit.com/r/thinkpad/comments/jq53yt/freezing_x270x260x250_official_fix_a_bit_lmao/}, but I haven't had to do this yet.
### Hardware support and chassis
-ThinkPad laptops generally have [url https://www.thinkwiki.org/wiki/Drivers Linux drivers for just about anything], you can freely control the different lights on the laptop or the precise fan speed.
+ThinkPad laptops generally have {url Linux drivers for just about anything;https://www.thinkwiki.org/wiki/Drivers}, you can freely control the different lights on the laptop or the precise fan speed.
Since this was my first machine in the line, I found this out after getting it, which is a huge advantage to be sure.
Also, ThinkPad laptops are usually made with a thick high quality plastic and the X270 is no exception.
@@ -122,7 +124,7 @@ But this is in no way a deal-breaker, and the connector is much beefier than nor
### Batteries
-Something absolutely amazing is that the X270 comes with two, count them, [=TWO=] batteries - one internal and one (removable) external.
+Something absolutely amazing is that the X270 comes with two, count them, {b TWO} batteries - one internal and one (removable) external.
The last time I saw a removable battery was on the old family laptop from 2011, and this one has an additional internal one.
Do I even need to explain why this is awesome?
@@ -135,7 +137,7 @@ The trade-off is that the 52 Wh battery is much thicker, so it's not flush with
### Keyboard and power button
-Speaking of the devil, unfortunately, the X270 doesn't have the fantastic old keyboards on older ThinkPad models (though, if you are determined, [url https://www.youtube.com/watch?v=Fzmm87oVQ6c you could probably put an old one in the laptop]).
+Speaking of the devil, unfortunately, the X270 doesn't have the fantastic old keyboards on older ThinkPad models (though, if you are determined, {url you could probably put an old one in the laptop;https://www.youtube.com/watch?v=Fzmm87oVQ6c}).
However, comparing to other laptop keyboards, I would say this one isn't too bad, it's not anything amazing, but it better than a good amount of others.
Compared to the S730, it's has a much longer key travel and the keys generally feel a lot clicker.
@@ -145,7 +147,7 @@ The X270 is much more normal, though the square brackets and pipe keys are half-
The Fn key is to the left of the Ctrl key, but in the BIOS you can swap them around, so that's not a problem.
My only issue is with the spacebar, because the actual switch isn't in the center of the key, but to the left of it, and I mostly press the spacebar with my right hand, so when I don't absolutely slam it, the key press could just barely not register.
-The only reason I'm talking about the power button at all is that, baked in the firmware, to register a press you have to [url https://bbs.archlinux.org/viewtopic.php?pid=1193137#p1193137 hold it down for 1-3 seconds], at least when shutting down.
+The only reason I'm talking about the power button at all is that, baked in the firmware, to register a press you have to {url hold it down for 1-3 seconds;https://bbs.archlinux.org/viewtopic.php?pid=1193137#p1193137}, at least when shutting down.
This isn't a bug, it's a feature, and it has come quite in handy, I've had friends casually press the power button on my S730 and shut it off without me being able to react.
### Trackpoint and mouse pad
@@ -183,30 +185,31 @@ My only issue is that the fan curve prioritizes silence a little too much on low
It's by no means outrageous, the fan kicks in at a little bit above 45-50 degrees Celsius, which is fine, but when the CPU is close to or at those temperatures, the chassis starts getting a little warm.
During the summer my left hand stars sweating a little bit more, which can be quite uncomfortable.
-Of course, as already mentioned, we have drivers for everything, so I installed [url https://github.com/vmatare/thinkfan thinkfan].
+Of course, as already mentioned, we have drivers for everything, so I installed {url thinkfan;https://github.com/vmatare/thinkfan}.
With it, I configured the fan to spin up on those lower temperatures and left the automatic configuration intact when we start getting warmer:
-```yaml
-'include ./thinkfan.yaml
+'def LANG yaml
+```
+'snippet 1 $ ./thinkfan.yaml
This may shorten the fan lifespan, since it will be running more, but for me it's worth it.
### Pricing
-As I already said, I got my X270 second hand from [url https://subincho.com/index.php subincho.com], with only a few cosmetic issues; it's practically brand new.
+As I already said, I got my X270 second hand from {url subincho.com;https://subincho.com/index.php}, with only a few cosmetic issues; it's practically brand new.
ThinkPads are quite often favorites for businesses, so now is the time when those 6 year old machines get thrown out on the second hand market.
I'll work with the final price of 340 euro, which includes the monitor upgrade and 52 Wh external battery, since that's when the machine goes from good to fantastic.
I live in Bulgaria, so depending on where you live, there might be better offers, but even with a doubled price, you won't find anything brand new that is as good.
-Let's look at the listings in [url https://www.jarcomputers.com/ JAR computers], since I've found their pricing and availability to be quite normal for online shops (and the physical shops almost always offer fewer devices with a much higher price).
+Let's look at the listings in {url JAR computers;https://www.jarcomputers.com/}, since I've found their pricing and availability to be quite normal for online shops (and the physical shops almost always offer fewer devices with a much higher price).
So, 340 * 2 = 640 euro, or roughly 1300 Bulgarian Lev.
-At the time of writing, [url https://www.jarcomputers.com/Laptopi_cat_2.html?ref=all&fprop[4413\][48266=\]48266&fprop[4413\][48256=\]48256&order=-1&&fprice[price-filter-other=\]p_from-1100-p_to-1600 searching for a ~13 inch laptop at around that price range] yields only two results: a [url https://www.jarcomputers.com/microsoft-surface-laptop-go-2-8qc-00024-prod-nbmicrosoft8qc00024.html Microsoft Surface Laptop Go 2] and [url https://www.jarcomputers.com/ms-surface-laptop-go-tnv-00009-prod-nbmicrosofttnv00009.html Microsoft Surface Laptop Go], both of which are on sale (with the second's original price being ~2300 lev, around ~1100 euro, three times the price).
+At the time of writing, {url searching for a ~13 inch laptop at around that price range;https://www.jarcomputers.com/Laptopi_cat_2.html?ref=all&fprop[4413\][48266=\]48266&fprop[4413\][48256=\]48256&order=-1&&fprice[price-filter-other=\]p_from-1100-p_to-1600} yields only two results: a {url Microsoft Surface Laptop Go 2;https://www.jarcomputers.com/microsoft-surface-laptop-go-2-8qc-00024-prod-nbmicrosoft8qc00024.html} and {url Microsoft Surface Laptop Go;https://www.jarcomputers.com/ms-surface-laptop-go-tnv-00009-prod-nbmicrosofttnv00009.html}, both of which are on sale (with the second's original price being ~2300 lev, around ~1100 euro, three times the price).
Both have soldered on RAM with no slots, so it cannot be upgraded, both have 1536x1024 displays with no anti-glare, that are glued to the screen bezel, both miss the Ethernet and HDMI ports, and since they aren't (older) ThinkPads, you won't get the TrackPoint or mouse buttons or Linux driver support or removable battery.
-Of course, they have their own positives, the display is a touchscreen and they score [url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-1035G1+%40+1.00GHz&id=3558 2.3] and [url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-1135G7+%40+2.40GHz&id=3830 3.0] times higher on CPU mark respectively, but still, you get so much more with the ThinkPad for half the price.
+Of course, they have their own positives, the display is a touchscreen and they score {url 2.3;https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-1035G1+%40+1.00GHz&id=3558} and {url 3.0;https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-1135G7+%40+2.40GHz&id=3830} times higher on CPU mark respectively, but still, you get so much more with the ThinkPad for half the price.
Now, in all fairness, this is comparing a second hand laptop to a brand new one, for double the price you could get a lot more in a second hand machine.
-Looking at the same place from which I bought my X270, they currently have [url https://subincho.com/laptopi?product_id=15309 a ThinkPad L13] for ~510 euro, which only misses out on the Ethernet port and external battery, but instead provides [url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-10510U+%40+1.80GHz&id=3549 double the CPU mark].
+Looking at the same place from which I bought my X270, they currently have {url a ThinkPad L13;https://subincho.com/laptopi?product_id=15309} for ~510 euro, which only misses out on the Ethernet port and external battery, but instead provides {url double the CPU mark;https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-10510U+%40+1.80GHz&id=3549}.
And that's only one site, if you look around enough you could probably find even better deals, but the 340 euro is still a really good deal.
## Conclusion
diff --git a/src/blog/thoughts-on-minecraft-design/index.du b/src/blog/thoughts-on-minecraft-design/index.du
new file mode 100644
index 0000000..74962cd
--- /dev/null
+++ b/src/blog/thoughts-on-minecraft-design/index.du
@@ -0,0 +1,331 @@
+# Thoughts on Minecraft's design
+
+'define expected-reading ? min
+'define created 03 May 2026
+'define edited 03 May 2026
+[$pagenav]
+
+It seems that in recent years, Mojang has become more and more out of touch with their flagship game and community.
+Updates seem to introduce more and more change which nobody asked for, while long-standing issues are left unaddressed.
+
+But this does bring up the question: what makes Minecraft good?
+In fact, what made it so good as to become the most sold game of all time?
+
+Well, I can't say I'm a reputable authority on this topic, in any sense or form.
+However, I still believe I've been able to reach some part of the truthful answer.
+
+Let's talk.
+
+## What does Mojang think of Minecraft?
+
+Let's explore what Mojang has to say.
+And what better place to that with the [url https://archive.org/details/minecraftgamedesign_202308/Jeb_ENG Minecraft Game Design book from Jens Bergensten] (Jeb), the lead designer of Minecraft since 2011.
+
+I do not want to disect every single word he has written, so we'll only talk about some of the more relevant design principles he outlines.
+
+### Bad things happen...
+
+Here Jeb argues that most accidents that happen are completely avoidable, and the few that aren't have low impact on player's work.
+This sounds reasonable, and is how Minecraft has worked for most of its life.
+
+By properly lighting up areas you don't allow mobs to spawn and potentially kill you, blow your buildings up or kill your villagers.
+By putting up walls and iron golems around your base or village you keep your villagers safe and sound.
+
+However, I would like to argue this is not where Minecraft shines.
+I mean, which do you remember more fondly:
+.ordered
+1. The 30 minutes you spent spelunking in deep winding caves and ravines, mining ores, killing enemies, having to hide to replenish your health before lunging back in.
+ All the while you're getting farther away from the surface and with more and more valuable loot, making your escape more difficult, more costly and more risky.
+2. The 30 hours you've spent in your base, walking around, looking at your builds, transfering items or mobs around.
+
+I would bet it's the first.
+Because at the end of the day, what makes games fun is having a challenge, taking on risk and ultimately "winning".
+But by making all accidents avoidable, you make most challenges trivial, since there is no winning if there is no losing.
+
+Of course, there are contra-arguments: having creepers spawn on your parkour is less challenging and much more frustrating.
+
+My point is that certain accidents should be avoidable in certain situations, but never all and those that are left should have impact, enough to drive up risk.
+
+### Items should be multi-purpose
+
+I completely agree with this point.
+
+However, in the second paragraph, he contradicts himself, giving the totem of undying as an example for that principle.
+He argues that it is ok for the item to have a single use since it has sufficient gameplay impact??
+
+Shouldn't the principle then be "Make items more impactful"?
+To me at least, this feels closer to what Mojang does in reality.
+
+And nobody says an item can't be both impactful and have multiple uses.
+For example, what if you could give the totem of undying to other mobs?
+You wouldn't be able to get it back once given, but the mob will be able to survive twice the amount of damage, exceptionally impactful for villagers or the random chicken you've grown attached to.
+
+So, there are two different uses: either for protecting you or protecting another creature.
+These totems are fairly hard to acquire, so it opens up a dillema on who needs it more, bringing a challenge which makes it more interesting and fun.
+
+The principle should be followed as often as possible.
+
+### You are not wearing a HUD
+
+Jeb argues that you should have items which present in-game information, like the map, compass and clock, instead of having something like the F3 debug screen, saying how he is personally an opponent to it.
+
+I feel this idea is out of touch.
+
+### Finding things is fun. Searching for them is not.
+
+Again, I completely agree with this point.
+
+But Jeb, for a second time, contradicts himself.
+As examples he lists exploration maps in woodland mansions and bubble columns in under-water ruins.
+
+Meanwhile, woodland mansions are the epitomy of searching for hundreds and hundreds of blocks for the one biome they spawn in, and then searching for further hundreds and hundreds of blocks to find them.
+He also talks about the under-water ruins like they are hidden... they are not... if you see the bubble column you'll see them, and it could be argued that the bubble column does more to obscure your vision...
+And don't get me started on trial chambers and heavy cores.
+
+### Real-life animals should be friendly
+
+I do not understand this restriction, how real-life animals could at most defend themselves but to never be truly dangerous.
+
+Why?
+What does this achieve?
+There is nothing interesting in seeing a recogniseable creature which serves as a mostly defensless looting table.
+
+I would argue, the opposite is more interesting.
+Make a majority of animals friendly, but then add some hostile animals.
+They will serve as enemies during the day, adding some challenge outside of night.
+Why wouldn't it be at least interesting if you had an animal, which is instinctively dangerious (like a bear or lion) or which is a surprise, catching you off-guard?
+
+I feel the polar bear should've been hostile and the shouldn't have removed the killer rabbit from spawning.
+That would make game interactions more interesting.
+
+### Hostile mobs should be unique
+
+I also don't understand this restriction.
+
+Most older mobs aren't that unique: zombies, skeletons, witches, the ender dragon (which is a dragon in itself).
+The creeper famously was created when Notch screwed up the proportions for pig models.
+
+Although entirely speculations on my end, I would further argue the green design came from the idea that the creeper should "blend" in the forest.
+The zombie pigman also probably came from that: imagine putting the pig texture on a creeper.
+That does kind of look like a person, so thats how he worked on the original pigman and from there the idea of a zombified pigman was fairly straight-forward.
+
+The more unique hostiles still have some sort of reasoning to them: the ender man is just a tall skinny player model, ghasts look kind of like a squid, breezes are effecitvely blaze rods with a head and slimes are just a big cube.
+
+I feel Jeb is not giving enough credit to how familiar and recognizeable the older mobs are.
+For me, the more "unique" hostiles are less interesting: guardians, phantoms, shulkers.
+And from the newer additions, I like the more "relateably" shaped: wardens are similar to golems, ravagers remind me of elephants, hoglins are just big fat hogs.
+
+### Human characters are human beings
+
+Yet another fairly strange decision.
+
+It could be argued non-player human beings should be rare, but excluding them entirely feels baseless.
+I mean, one of the most iconic things in Minecraft is Herobrine.
+Imagine if they added him as a very rare hostile mob which just stands there to haunt you.
+
+Or if they made "mimicks", mobs which look like friendly people but aren't.
+A good amount of interesting mechanics and interactions just rejected.
+
+### Keep it vanilla
+
+Here the point is that the game should be expanded in all directions.
+
+This actually agrees with our earlier analysis, if Minecraft is a collection of mechanics, then you should expand on all mechanics in "equal" fasion.
+
+### No item is truly unique
+
+The fourth point which baffles me.
+Jeb argues that, for example, adding named weapons like a crossbow named "Heartseeker" would "add connection points between worlds that would make them feel less special".
+
+I believe the effect is the opposite: "Hey, I found this epic weapon in a mineshaft! It has some cool enchantments and little durability, I guess it is the weapon of an old hero".
+And finding it in different world wouldn't make it less special, you could think "the hero was here too".
+
+My point is that named weapons would add some story to the world and could serve as a good introduction to enchantments if they're more easily available.
+
+### In resume
+
+All in all, I'm not very satisfied with many of the restrictions Jeb has emposed on the game.
+Many, if lifted, would open up the game to more interesting experiences and others seem to not be followed at all, or at least not for big important features of the game.
+
+I believe Minecraft should be more varied, not shying away from storytelling, while also being grounded and somewhat intuitive.
+More random and unexpected things should be able to happen, even if it hurts the player, since that offers challenge and risk, which makes the experience more fun.
+
+## What does Mojang do to Minecraft?
+
+As mentioned, it seems Jeb doesn't follow some of the principles he outlines.
+And other make the game worse, in my opinion.
+
+Let's now hear about it from the horse's mouth.
+We'll explore the changes in more notable updates after Notch stepped down as lead designer.
+
+### 1.1 - 1.5 (Redstone Update)
+
+For the first 1-2 years, updates were fairly inoffensive, adding beaches, bow enchantments, jungles, ocelots, iron golems, emeralds, block varieties, the wither, item frames, potatoes, carrots, anvils, zombie villagers and hoppers, droppers, comparator, quartz.
+
+There isn't much to say, you could argue that more food items were a mistake, since there is no real use for them.
+Wheat is still easy to gather, easy to grow, easy to craft in abundance and replenishes plenty of health.
+
+The redstone components are very useful, like the hopper and trapped chest.
+Let me remind you, before trapped chests, you couldn't place double chests next to each other.
+
+Quartz is also a great addition, since there aren't much white blocks.
+Although I'm slightly dissapointed they didn't add quartz structures, the quartz pillars really remind you of old roman/greek buildings.
+It would've been cool if you could find the large ruins of a pure white structure, on the background of the monotonous red netherack.
+
+### 1.6 (Horse Update)
+
+Horses and Donkeys were a great addition, but I dislike the breeding mechanic.
+It is extremely annoying to have to find and then selectively breed them to have a horse or donkey with the highest speed and/or jump.
+
+I might've done the breeding work once, and it wasn't fun at all.
+Quite often I skip on horses, since quite often you'll ones which are too slow or jump too low.
+
+They should've simplified it, for example, make horses and donkeys spawn with a random set of 3-5 predetermined speed & jump values.
+When you breed them, you'll have a high chance of taking the better trait of the two parents.
+
+It will be easier to compare and manage horses/donkeys and breeding would be more viable.
+
+### 1.7 (The Update that Changed the World)
+
+Most changes are fine.
+
+However, they did replace the rose with a poppy, mostly due to pedantics, since "roses are flowering shrubs, not flowers" (from the [url https://archive.org/details/minecraftgamedesign_202308/Jeb_ENG Minecraft game design book]).
+This sets a bad precedence, that game features will be determined more by the way they work in real life than is reasonable to do in the game.
+
+Another change is in the world generator with a lot of new biomes.
+The major difference between the old generation is that before land was somewhat separated in continents by large oceans, while now the world is one large mass with huge "ocean" lakes.
+This is contrary to how it works in real life, but here I would argue it's a worse decision.
+
+Land masses before were plenty large to begin with, you were never really missing a biome, for which you needed to visit another continent.
+And it made it more interesting, an ocean was an ocean, exploring the new continent was a cool idea.
+
+Although I will commend the mesa biome, since it was more colorful with the different clay layers and provided a more efficient way to acquire clay, easing up some of the grinding.
+
+### 1.8 (Bountiful Update)
+
+On one hand, this update introduced the slime block.
+This block is fantastic, as new interesting effects emerge: bouncing players and items around, as well as making flying machines.
+It can serve many different purposes and integrates quite seemlessly with the rest of the game.
+
+However, on the other hand, this update introduces the ocean monument and guardians.
+As mentioned, guardians have a very weird design, both being inspired from reality with their tail and also being completely unrelated to anything.
+
+And for fighting through them and the elder guardian, you get a sponge and some gold?
+Quite underwhelming, also mining fatigue is annoying more than challenging or interesting and the guardians are the only mobs which have the laser ability.
+
+This sets another bad precedent for the future: structures and mobs, which are exclusive to some specific structure which you have to find.
+
+They should've added more mechanics around it.
+For example, what if you get a guardian eye as a weapon drop, allowing you to fire the beam?
+Or why not make them like large squid-like creatures, reminiscent of ghasts which fire a new projectile?
+
+### 1.9 (Combat Update)
+
+This is a very contravertial update, to this day.
+
+To be honest, I'm on the fence about weapon cooldown.
+
+The shield too
+
+I like the fact that they added to the end dimention, so it is not a one-off island, however they added too little.
+There should've been more structures, end cities shouldn't have been so rare (especially the variants with the ship) and elytras are broken.
+
+Being able to fly is cool and all, but it immediately destroys all other forms of transport.
+Also, remember that thing about having mobs exclusive to some specific structure?
+
+
+### 1.10 -
+
+
+
+
+
+
+
+
+
+## What is Minecraft?
+
+No, seriously!
+Everybody's first thought is "a video game", closely followed by "an open-world sandbox".
+But what does that mean in reality?
+
+Let's think about the "sandbox" genre, about games like Garry's mod, Stardew Valley, Kerbal Space Program.
+Wait, those last two aren't sandbox games, they're sims!
+Or are they?
+
+I mean, [url https://steamdb.info/charts/?tagid=3810 SteamDB] lists them as such, so does [url https://www.thegamer.com/best-sandbox-games/ TheGamer].
+But neither [url https://en.wikipedia.org/wiki/Category:Sandbox_games Wikipedia], nor [url https://www.metacritic.com/browse/game/all/sandbox/ Metacritic] do.
+We could argue which source is more reputable than the other, but what's more important is how people view them in general, not who is technically right.
+And it seems many believe either side.
+
+However, even between the universally accepted sandbox games we find suspicious differences.
+Minecraft, Terraria and Garry's mod seem much more closely related to each other, than to Subnautica or ARK: Survival Evolved.
+
+So, I ask again: what is Minecraft?
+What game is it?
+What direction is it supposed to go in?
+Should it lean more on bosses like Terraria, or more on PVP like ARK, or more on story like Subnautica?
+
+Since we're asking all these question, what is a video game anyway?
+
+### What is a game?
+
+I mean, [url https://en.wikipedia.org/wiki/Video_game Wikipedia] defines it as:
+
+.quote
+A video game, [...] is an electronic game that involves interaction with a user interface or input device [...] to generate visual feedback from a display device, most commonly shown in a video format [...]
+
+But this leaves much to be desired: wouldn't a webpage be considered a videogame too?
+Or a random number generator?
+I mean, even your operating system creates visual feedback from a display device via inputs, is Windows 11 just one terribly unoptimized modern day AAA title?
+
+The [url https://dictionary.cambridge.org/dictionary/english/video-game Cambrige Dictionary] comes a little closer:
+
+.quote
+A game in which the player controls moving pictures on a screen by pressing buttons
+
+The "moving pictures" part is kind of innacurate, what about all of those challenges where people play games blindfolded?
+Although technically not done, it is equivalent to removing all graphics processing in the game, while still leaving it a "video game".
+
+But ok, now, what is a game [url https://dictionary.cambridge.org/dictionary/english/game Cambrige]:
+
+.quote
+An entertaining activity or sport [...]
+
+Ok... but what is entertainment anyway?
+I would consider organizing the icons on your desktop at least a little bit entertaining.
+Drawing or animating is entertaining too, is Paint.NET a video game?
+
+### Making a decision
+
+These pedantics could go on until the end of time.
+At the end of the day, the only true answer is that "a video game is something which we've decided call a video game".
+That deciding factor in itself rests upon some loosely-defined characteristics; games look, feel, behave, are marketed and are engaged in certain ways.
+
+Let's try something else.
+Since we can't really define what kind of game Minecraft is, nor what constitutes a game, let us ask:
+
+[=Is Minecraft a game?=]
+
+Seriously!
+Comparing with other games, it has an "ending" when you kill the Ender Dragon, but you can continue playing after that, and it is not even mandatory.
+It has building mechanics, but again, they are more or less optional, you could only play PVP on servers.
+It has automation mechanics with redstone, but again, they are optional, and you could argue most players only ever lightly interact in them.
+It has PVP mechanics, but you could play for hundreds of hours on a peaceful single-player world.
+
+It seems that almost all other sandbox games have some sort of goal and some set of core mechanics which the vast majority of players will always use.
+You [*can*] beat Stardew Valley without ever framing, but you wouldn't find a huge portion of players doing that.
+You could also beat Terraria without attacking, but again, very few people will do so.
+
+All of this bring me to the following conclusion:
+
+[= Minecraft is a tool!=]
+
+More precisely, it is a collection of well-interacting game mechanics, which are used to make (or play) your own "game".
+Your experience is entirely determined by the game, or maybe we should call it "subgame", which you play when playing Minecraft.
+
+
+
+The obvious impliciation from our reasoning is that you improve Minecraft by adding depth to existing game mechanics and adding new mechanics which integrate well with most other mechanics.
+But is that true?
diff --git a/src/blog/turn-off-notifications-windows/index.du b/src/blog/turn-off-notifications-windows/index.du
index b85f811..4215d81 100644
--- a/src/blog/turn-off-notifications-windows/index.du
+++ b/src/blog/turn-off-notifications-windows/index.du
@@ -1,27 +1,27 @@
-# How to turn off notifications on Windows
+'def title How to turn off notifications on Windows
+'def desc What if you need to concentrate on some work, and you don't want to have your notifications show up while doing so? Or, what if some apps just put out notifications too often? Well, this is how to disable notifications.
-'define expected-reading 1 min
-'define created 01 November 2021
-'define edited 01 November 2021
-[$pagenav]
+# {title}
+
+{pagenav 1 min;01 November 2021;01 November 2021}
What if you need to concentrate on some work, and you don't want to have your notifications show up while doing so? Or, what if some apps just put out notifications too often? Well, this is how to disable notifications:
:ordered
-1. In the [*Search bar*] type in [=Notification=]. The [=Notification & actions settings=] option should show up, click it
+1. In the {i Search bar} type in {b Notification}. The {b Notification & actions settings} option should show up, click it
- [image ./img/windows-search-notifications.png]
+ {img ./img/windows-search-notifications.png}
-2. If you want to turn off all notifications, switch the [=Get notifications from apps and other senders=] to the [*Off*] position
+2. If you want to turn off all notifications, switch the {b Get notifications from apps and other senders} to the {i Off} position
- [image ./img/windows-settings-notifications-off.png]
+ {img ./img/windows-settings-notifications-off.png}
.p
- [*Note: "Suggest best ways", "Welcome Experience" and "Tips and tricks" will still show up, you'll have to uncheck those individually*]
+ {i Note: "Suggest best ways", "Welcome Experience" and "Tips and tricks" will still show up, you'll have to uncheck those individually}
.p
- If you want to turn off notifications for specific apps, scroll down to the [=Get notifications from these senders=], find the applications you want to turn off notifications for and flick the switch
+ If you want to turn off notifications for specific apps, scroll down to the {b Get notifications from these senders}, find the applications you want to turn off notifications for and flick the switch
- [image ./img/windows-settings-notifications-application.png]
+ {img ./img/windows-settings-notifications-application.png}
3. Finally, you can simply close the window
diff --git a/src/blog/virt-manager-freeze-on-browse/index.du b/src/blog/virt-manager-freeze-on-browse/index.du
index 067c86d..a5646cf 100644
--- a/src/blog/virt-manager-freeze-on-browse/index.du
+++ b/src/blog/virt-manager-freeze-on-browse/index.du
@@ -1,23 +1,23 @@
-# virt-manager freezing up when clicking Browse in any window
+'def title virt-manager freezing up when clicking Browse in any window
+'def desc This issue is caused by some sort of problem with the storage pools when it tries to load them. I was able to fix it by pretty much deleting that folder, but you really should just rename it.
-'define expected-reading 1 min
-'define created 01 January 2023
-'define edited 01 January 2023
-[$pagenav]
+# {title}
+
+{pagenav 1 min;01 January 2023;01 January 2023}
The title explains what the problem is.
You might've also noticed that it spikes a CPU core's utilization to 100%.
Furthermore everything works if you enter a file location manually in the corresponding input field, it's just that darn button.
-'footnote storage-pools The storage pool is just a folder with files that store what locations can be used by virtual machines (more info [url https://libvirt.org/storage.html here]). In the case of virt-manager, pretty much every time you select any folder or file, a folder entry gets added there.
+'footnote storage-pools The storage pool is just a folder with files that store what locations can be used by virtual machines (more info {url here;https://libvirt.org/storage.html}). In the case of virt-manager, pretty much every time you select any folder or file, a folder entry gets added there.
-This issue is caused by some sort of problem with the storage pools[$storage-pools] when it tries to load them.
+This issue is caused by some sort of problem with the storage pools{storage-pools} when it tries to load them.
I was able to fix it by pretty much deleting that folder, but you really should just rename it:
-```shell
+```sh
sudo mv /etc/libvirt/storage /etc/libvirt/storage-broken
libvirt automagically regenerates the original folder, so you might need to restart it:
-```shell
+```sh
sudo systemctl restart libvirtd
diff --git a/src/blog/when-a-language-forces-simpler-thinking/index.du b/src/blog/when-a-language-forces-simpler-thinking/index.du
index fcf3c7e..c99ebd0 100644
--- a/src/blog/when-a-language-forces-simpler-thinking/index.du
+++ b/src/blog/when-a-language-forces-simpler-thinking/index.du
@@ -1,15 +1,15 @@
-# When a language forces simpler thinking
+'def title When a language forces simpler thinking
+'def desc An interesting situation where changing how you think results in a better solutions than trying to adapt your original idea
-'define expected-reading 5 min
-'define created 13 December 2022
-'define edited 13 December 2022
-[$pagenav]
+# {title}
-This year I decided to join the [url https://adventofcode.com/2022 2022 Advent of Code] event.
-The exercise [url https://adventofcode.com/2022/day/7 on the 7th day] involved storage of a folder structure: each folder would have a name, files, and other folders in itself.
+{pagenav 5 min;13 December 2022;13 December 2022}
+
+This year I decided to join the {url 2022 Advent of Code;https://adventofcode.com/2022} event.
+The exercise {url on the 7th day;https://adventofcode.com/2022/day/7} involved storage of a folder structure: each folder would have a name, files, and other folders in itself.
For the task itself, you don't actually need to store the files, just the sum of their (and of those in subfolders) size, so a folder can be represented as a name, a number and multiple other folders.
-My solutions are written purely in [url https://en.wikipedia.org/wiki/Common_Lisp#Syntax Common Lisp]: a programming language where everything is represented as a list of values. A value might be another list or a non-list value, like a number.
+My solutions are written purely in {url Common Lisp;https://en.wikipedia.org/wiki/Common_Lisp#Syntax}: a programming language where everything is represented as a list of values. A value might be another list or a non-list value, like a number.
So I thought I could represent each folder as a list, where the first item is it's name, second is file size sum and the rest are subfolders, something like this:
```
@@ -21,7 +21,7 @@ Name File size sum Subfolder "e" in "a"
| |
Subfolder "a" in "/" Subfolder "d" in "/"
-Now, after parsing a file, you'll need to update the file size sum in the [=current=] folder [=and=] in the [=parent=] folder.
+Now, after parsing a file, you'll need to update the file size sum in the {b current} folder {b and} in the {b parent} folder.
To do such a thing, you would either need to
.bulleted
@@ -49,16 +49,14 @@ Name | File size sum
| | |
At index 0 is parent "/" Parent is "a" Parent is "/"
-'footnote day7 A potential improvement would be to use CLOS to store each folder as it's own object, but this worked fine and I really wanted to spare reading on CLOS at that time.
-
-Now this solution worked great! With this I was able to [url https://gitlab.com/Syndamia/advent-of-code/-/tree/main/2022/Day07 solve] both tasks easily.[$day7]
+Now this solution worked great! With this I was able to {url solve;https://gitlab.com/Syndamia/advent-of-code/-/tree/main/2022/Day07} both tasks easily.{fn A potential improvement would be to use CLOS to store each folder as it's own object, but this worked fine and I really wanted to spare reading on CLOS at that time.}
#### Appendix
In the exercise, you have commands for navigating between folders.
-Going up a folder is trivial, but folders can have duplicate names if they're inside different parent folders, so going to a sub folder requires to search by it's name [*and*] parent index.
+Going up a folder is trivial, but folders can have duplicate names if they're inside different parent folders, so going to a sub folder requires to search by it's name {i and} parent index.
-Surprisingly enough, in my solution [url https://gitlab.com/Syndamia/advent-of-code/-/tree/main/2022/Day07/part-one.cl#L15-17 (lines 15-17)], I just search from the end to the beginning of all parsed folders for a name.
+Surprisingly enough, in my solution {url (lines 15-17);https://gitlab.com/Syndamia/advent-of-code/-/tree/main/2022/Day07/part-one.cl#L15-17}, I just search from the end to the beginning of all parsed folders for a name.
This works fine for this exact task and exact inputs, however in general this isn't correct. In a structure like this:
```
@@ -92,8 +90,8 @@ $ cd ..
$ cd ..
$ cd a
-'footnote mkfile [`mkfile`] is like [`touch`], but you could specify a size and the file will be filled with that many zeroes. It seems to exist solely in [url https://docs.oracle.com/cd/E26502_01/html/E29031/mkfile-1m.html Solaris] (as a system administration command) and [url https://ss64.com/osx/mkfile.html MacOS]. I mentioned it and not [`touch`], since the latter only creates empty files, which wouldn't contribute to the total file size sum.
-
-The last [`\$ cd a`] actually puts you into [`/b/a/`], not [`/a/`].
+The last {` \$ cd a} actually puts you into {` /b/a/}, not {` /a/}.
The main thing that saves us (me) is that you can only change directory and list structure (in current directory), so you would only ever be visiting a folder once.
-If a folder's contents were [`ls`]'d more than once, or they could change (for example having an [`mkfile`] [$mkfile] command), a proper search would be required.
+If a folder's contents were {` ls}'d more than once, or they could change (for example having an {` mkfile} {fn {` mkfile} is like {` touch}, but you could specify a size and the file will be filled with that many zeroes. It seems to exist solely in {url Solaris;https://docs.oracle.com/cd/E26502_01/html/E29031/mkfile-1m.html} (as a system administration command) and {url MacOS;https://ss64.com/osx/mkfile.html}. I mentioned it and not {` touch}, since the latter only creates empty files, which wouldn't contribute to the total file size sum.} command), a proper search would be required.
+
+{footnotes}
diff --git a/src/blog/windows-run-dialog/index.du b/src/blog/windows-run-dialog/index.du
index c5de7b1..5269555 100644
--- a/src/blog/windows-run-dialog/index.du
+++ b/src/blog/windows-run-dialog/index.du
@@ -1,172 +1,175 @@
-# Windows Run dialog
+'def title Windows Run dialog
+'def desc On Windows, most often you run an application by finding and double-clicking it's exe file. What a lot of people don't realise is that you can launch any application or open any file you want by typing a single command. That can be achieved inside the Run dialog.
-'define expected-reading 3 min
-'define created 04 October 2021
-'define edited 31 October 2021
-[$pagenav]
+# {title}
+
+{pagenav 3 min;04 October 2021;31 October 2021}
:contents
:numbered
-1. [url #opening-the-run-dialog Opening the Run dialog]
+1. {uhref Opening the Run dialog}
-2. [url #commands Commands]
+2. {uhref Commands}
.numbered
- 1. [url #folders Folders]
- 2. [url #programs Programs]
- 3. [url #windows-settings Windows settings]
+ 1. {uhref Folders}
+ 2. {uhref Programs}
+ 3. {uhref Windows settings}
-3. [url #for-more For more]
+3. {uhref For more}
-On Windows, most often you run an application by finding and double-clicking it's [`.exe`] file. What a lot of people don't realise is that you can launch any application or open any file you want by typing a single command. That can be achieved inside the [=Run dialog=].
+On Windows, most often you run an application by finding and double-clicking it's {` .exe} file. What a lot of people don't realise is that you can launch any application or open any file you want by typing a single command. That can be achieved inside the {b Run dialog}.
## Opening the Run dialog
To open the Run dialog, you can either:
-[*A)*] Press [`Win + R`] key combination
+{i A)} Press {` Win + R} key combination
or
-[*B)*] Right click on the Windows menu, and then press [`Run`]
+{i B)} Right click on the Windows menu, and then press {` Run}
-[image ./img/open-run-windows-menu.png]
+{img ./img/open-run-windows-menu.png}
## Commands
-[image ./img/run-dialog.png]
+{img ./img/run-dialog.png}
### Folders
-You can open any folder by typing in it's [=full path=]. So, if you have a folder named [`Work`] inside your [`Documents`] folder, the full path will be something like [`C:\Users\John\Documents\Work\\`].
+You can open any folder by typing in it's {b full path}. So, if you have a folder named {` Work} inside your {` Documents} folder, the full path will be something like {` C:\Users\John\Documents\Work\\}.
-If your desired folder is directly in your account folder, so [`Desktop`], [`Documents`], [`Pictures`], etc. you can just type in the name of the folder. For example, if you want to open your [`Pictures`] folder, just type in [`pictures`] and it will be opened.
+If your desired folder is directly in your account folder, so {` Desktop}, {` Documents}, {` Pictures}, etc. you can just type in the name of the folder. For example, if you want to open your {` Pictures} folder, just type in {` pictures} and it will be opened.
There are, of course, some more special location, some of which are:
-.table_2
+.table
+.2
|= Command
|= Location
-|: [`%ProgramFiles%`]
+|: {` %ProgramFiles%}
|: Program Files Folder
-|: [`%AppData%`]
+|: {` %AppData%}
|: User's App Data Folder
-[=Bonus=]: [`%appdata%\Microsoft\Windows\Start Menu`] will open the Start Menu folder, from which you can edit what goes inside your start menu.
+{b Bonus}: {` %appdata%\Microsoft\Windows\Start Menu} will open the Start Menu folder, from which you can edit what goes inside your start menu.
### Programs
-You can always run any application by typing in it's full path. So, to launch something like FireFox, you'll need to type in [`C:\Program Files\Mozilla Firefox\firefox.exe`].
+You can always run any application by typing in it's full path. So, to launch something like FireFox, you'll need to type in {` C:\Program Files\Mozilla Firefox\firefox.exe}.
But, whats more important is that you can more easily launch some Windows apps, like Calculator or Control Panel. Here is a list of commands and the application they launch:
-.table_2
+.table
+.2
|= Command
|= Application
-|: [`calc`]
+|: {` calc}
|: Calculator
-|: [`mspaint`]
+|: {` mspaint}
|: Microsoft Paint
-|: [`snippingtool`]
+|: {` snippingtool}
|: Snipping Tool
-|: [`notepad`]
+|: {` notepad}
|: Notepad
-|: [`sndvol`]
+|: {` sndvol}
|: Volume Mixer
-|: [`soundrecroder`]
+|: {` soundrecroder}
|: Sound Recorder
-|: [`wuapp`]
+|: {` wuapp}
|: Windows Updates
-|: [`shutdown`]\*
+|: {` shutdown}\*
|: Shutdown or restart computer
|:
|:
-|: [`cmd`]
+|: {` cmd}
|: Command Prompt
-|: [`powershell`]
+|: {` powershell}
|: Windows PowerShell
-|: [`control`]
+|: {` control}
|: Control Panel
-|: [`taskmgr`]
+|: {` taskmgr}
|: Task Manager
-|: [`msinfo32`]
+|: {` msinfo32}
|: System Information
-|: [`winver`]
+|: {` winver}
|: Windows Version Window
-|: [`cleanmgr`]
+|: {` cleanmgr}
|: Disk Cleanup
-|: [`dfrgui`]
+|: {` dfrgui}
|: Disk Cleanup (defragmentation)
-|: [`mstsc`]
+|: {` mstsc}
|: Remote Desktop Connection
|:
|:
-|: [`regedit`]
+|: {` regedit}
|: Registry Editor
-|: [`msconfig`]
+|: {` msconfig}
|: System Configuration Settings
-|: [`dcomcnfg`]
+|: {` dcomcnfg}
|: Component Services
-|: [`sigverif`]
+|: {` sigverif}
|: File Signature Verification Tool
-\*: The [`shutdown`] command [url https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/shutdown requires parameters]:
+\*: The {` shutdown} command {url requires parameters;https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/shutdown}:
.bulleted
-- [`/s`] will shutdown in one minute
-- [`/r`] will restart in one minute
-- [`/t`] specifies after what amount of time to shutdown or restart (a number needs to be entered afterwards, so [`/t 0`] for immediate execution)
-- [`/f`] forces running applications to close (might result in data loss!)
+- {` /s} will shutdown in one minute
+- {` /r} will restart in one minute
+- {` /t} specifies after what amount of time to shutdown or restart (a number needs to be entered afterwards, so {` /t 0} for immediate execution)
+- {` /f} forces running applications to close (might result in data loss!)
### Windows settings
There are also many "shortcuts" to different Windows settings windows. Those include:
-.table_2
+.table
+.2
|= Command
|= Setting
-|: [`mmsys.cpl`]
+|: {` mmsys.cpl}
|: Sound Properties
-|: [`powercfg.cpl`]
+|: {` powercfg.cpl}
|: Power Options
-|: [`timedate.cpl`]
+|: {` timedate.cpl}
|: Time and Date Options
-|: [`ncpa.cpl`]
+|: {` ncpa.cpl}
|: Network Connections
|:
|:
-|: [`inetcpl.cpl`]
+|: {` inetcpl.cpl}
|: Internet Properties
-|: [`compmgmt.msc`]
+|: {` compmgmt.msc}
|: Computer Manager
-|: [`devmgmt.msc`]
+|: {` devmgmt.msc}
|: Device Manager
-|: [`diskmgmt.msc`]
+|: {` diskmgmt.msc}
|: Disk Management
-|: [`firewall.cpl`]
+|: {` firewall.cpl}
|: Windows Firewall
|:
|:
-|: [`sysdm.cpl`]
+|: {` sysdm.cpl}
|: System Properties
-|: [`services.msc`]
+|: {` services.msc}
|: Services
-|: [`comexp.msc`]
+|: {` comexp.msc}
|: Component Services
-|: [`gpedit.msc`]
+|: {` gpedit.msc}
|: Group Policy Editor
-|: [`lusrmgr.msc`]
+|: {` lusrmgr.msc}
|: Local Users and Groups
-|: [`certmgr.msc`]
+|: {` certmgr.msc}
|: Certificate Manager
-|: [`taskschd.msc`]
+|: {` taskschd.msc}
|: Task Scheduler
-|: [`fsmgmt.msc`]
+|: {` fsmgmt.msc}
|: Shared Folders
-[=Note=]: [`cpl`] stands for [*Control Panel Item*] and [`msc`] stands for [*Microsoft System Configuration*].
+{b Note}: {` cpl} stands for {i Control Panel Item} and {` msc} stands for {i Microsoft System Configuration}.
## For more
-For more commands, check out [url https://windowsruncommands.com/ windowsruncommands.com]. They have a much bigger list of commands and shortcuts you can use.
+For more commands, check out {url windowsruncommands.com;https://windowsruncommands.com/}. They have a much bigger list of commands and shortcuts you can use.